using YLErp.Abstract.DataProviders;
using YLErp.BLL;
using YLErp.BLL.Calculation;
using YLErp.Modules.DataProviderModule;
using YLErp.QdpModule;
namespace YLErp.Modules.CalculationModule
{
public class CCRService : YLBaseService
{
public CCRService(OptUserInfo userInfo) : base(userInfo)
{
}
public CCRService(YLBaseService baseService) : base(baseService)
{
}
///
/// 是否实时计算
/// 实时计算时传参不一样
///
public bool IsRealtime { get; set; }
private DateTime? _settlementDate = null;
///
/// 结算日期
///
public DateTime SettlementDate
{
get
{
return _settlementDate ?? SystemValueDate;
}
set
{
_settlementDate = value;
}
}
///
/// 要忽略计算的交易类型
///
private readonly List ignoreTradeTypes = new List()
{
"结构化交易",
"自定义交易"
};
///
/// 执行ccr计算
/// 原公式:CCR=MTM+k*(ADD-ON);最新的更改为:CCR=MTM+(ADD-ON)
/// MTM:持仓浮动盈亏
/// ADD-ON:假定未来盈亏
///
/// 要计算的交易;一般为某个客户的所有持仓交易
/// CCR算法必要参数
/// CCR算法必要参数
/// Key:交易Id:Value:CCR值
public Dictionary CalculationCCR(List trades, double j, double N)
{
var result = new Dictionary();
var add_onVal = CalculationADD_ON(trades, (int)(j * 244), (int)N, out var mtmVal);
if (add_onVal.Count != mtmVal.Count)
{
throw new Exception($"计算出错,结果数量不匹配:\r\nadd_on:{add_onVal.ToJson()}\r\nmtm:{mtmVal.ToJson()}");
}
foreach (var item in add_onVal)
{
result[item.Key] = mtmVal[item.Key] + item.Value;
}
return result;
}
///
/// 计算ADD_ON
/// 算法由国海提供
///
/// 要计算的交易;一般为某个客户的所有持仓交易
/// 计算要覆盖的交易日数量;一般为244的倍数
/// 计算时滚动价格的间隔;为国海算法中的N
/// 当前持仓交易持仓部分累计浮动盈亏;
/// Key:交易Id:Value:CCR值
private Dictionary CalculationADD_ON(List trades, int dayCount, int interval, out Dictionary mtmVal)
{
if (trades is null)
{
throw new ArgumentNullException(nameof(trades));
}
var calcTrades = trades.Where(O => !ignoreTradeTypes.Contains(O.TradeType)).ToList();
if (calcTrades.Count == 0)
{
throw new ServiceException("不存在可计算的交易");
}
var underlyingCodes = calcTrades.Select(O => O.UnderlyingCode);
var dateList = QdpCalendarHelper.AllBizDays(QdpCalendarHelper.BizDayShift(SettlementDate, -dayCount), SettlementDate);
dateList.Add(SettlementDate);
var settlementType = ConsGlobal.SettlePriceMode.GetSettlementType(valuedateBLL.SystemDate.EodSettlePriceMode);
var latestPriceProvider = IsRealtime ? (IPriceProvider)DataCacheProvider.GetUnderlyingDataSource() : new EodPriceProvider(SettlementDate).GetPriceProvider(settlementType);
var latestRiskResult = CalculatorHelper.CalculateRisksForTrades(SettlementDate, calcTrades, Enums.CalcScenarioEnum.EodSettlement, latestPriceProvider, QdpPricingRequest.PV_ONLY, settlementType: settlementType, isUseTradeVol: PS.Config.IsTradeVol, preciseTimeMode: false, canUseManual: true);
var priceProviderDict = new Dictionary();
var latestPvMap = new Dictionary();
// 日期维度 合计值 交易编号 浮动盈亏
var pvList = new List>>();
//var pricessss = new List();
for (int i = 0; i < dateList.Count; i++)
{
TradeRiskResult riskResult = null;
if (dateList[i].Date.Equals(SettlementDate.Date))
{
riskResult = latestRiskResult;
}
else
{
var priceProvider = new EodPriceProvider(dateList[i]);
priceProviderDict[dateList[i]] = priceProvider;
if (i < interval) { continue; }
var calcPriceProvider = new ManualPriceProvider();
//pricessss.Add("");
foreach (var code in underlyingCodes)
{
var currentPrice = priceProviderDict[dateList[i]].GetPrice(code, SettlementTypeEnum.ClosePrice);
var lastPrice = priceProviderDict[dateList[i - interval]].GetPrice(code, SettlementTypeEnum.ClosePrice);
var price = latestPriceProvider.GetPrice(code) * (currentPrice / lastPrice).Normalize();
//pricessss[i - 1] += $"{dateList[i].ToString("yyyy-MM-dd")}\t{code}\t{currentPrice}\t{lastPrice}\t{price}\t";
calcPriceProvider.SetPrice(code, price);
}
riskResult = CalculatorHelper.CalculateRisksForTrades(SystemValueDate, calcTrades, IsRealtime ? Enums.CalcScenarioEnum.Pricing : Enums.CalcScenarioEnum.EodSettlement, calcPriceProvider, QdpPricingRequest.PV_ONLY, settlementType: settlementType, isUseTradeVol: PS.Config.IsTradeVol, preciseTimeMode: false);
}
//ADD-ON合计规则
var pv = riskResult.Results.ToDictionary(
K => K.Trade.id,
V =>
{
if (!(V.Trade.MetaDic.TryGetValue(YLErp.DBModels.Consts.ConsTradeMetaKey.CCR_K, out var strK) && double.TryParse(strK, out var k)))
{
k = 1;
}
if (!latestPvMap.ContainsKey(V.Trade.id))
{
latestPvMap[V.Trade.id] = latestRiskResult.Results.Where(B => B.Trade.id == V.Trade.id).FirstOrDefault()?.ValueResult.Pv ?? 0;
}
return k * (V.ValueResult.Pv - latestPvMap[V.Trade.id]);
});
//System.Diagnostics.Debug.WriteLine(((double)i / dateList.Count).ToString("0.##%"));
pvList.Add(new KeyValuePair>(pv.Values.Sum(), pv));
}
//LogFactory.GetLogger().Info($"计算次数:{pvList.Count}\r\n{pvList.Select(O => O.Value).ToJson()}");
mtmVal = latestRiskResult.Results
.ToDictionary(
K => K.Trade.id,
V => V.ValueResult.Pv);
return pvList.OrderByDescending(O => O.Key).FirstOrDefault().Value;
}
}
}