453 lines
20 KiB
C#
453 lines
20 KiB
C#
using BaseOUDAL;
|
|
using YLErp.Abstract.DataProviders;
|
|
using YLErp.BLL;
|
|
using YLErp.Helpers;
|
|
using YLErp.Model;
|
|
using YLErp.Modules.CalculationModule;
|
|
using YLErp.Modules.DataProviderModule;
|
|
using YLErp.Modules.EodModule.SettlementModule;
|
|
using YLErp.Office;
|
|
using YLErp.QdpModule;
|
|
|
|
namespace YLErp.Modules.EodModule.QueryModule
|
|
{
|
|
/// <summary>
|
|
/// 东证日终存续交易导出服务
|
|
/// </summary>
|
|
public class DongZhengEodTradePositionExportService : YLBaseService
|
|
{
|
|
public DongZhengEodTradePositionExportService(OptUserInfo optUser) : base(optUser)
|
|
{
|
|
|
|
}
|
|
|
|
public void ExportDongZhengZipFile(DateTime valueDate)
|
|
{
|
|
|
|
if (QdpCalendarHelper.GetNonHoliday(valueDate) != valueDate)
|
|
{
|
|
throw new ServiceException($"所选日期'{valueDate:yyyy-MM-dd}'不是交易日!");
|
|
}
|
|
|
|
if (!DbContext.eodStatus.Any(n => n.ValueDate == valueDate && n.Status == "已收盘"))
|
|
{
|
|
throw new ServiceException($"所选日期'{valueDate:yyyy-MM-dd}'未收盘!");
|
|
}
|
|
|
|
List<eod_position_dz> eods = GetEodPosition(valueDate);
|
|
List<client_dz> clients = GetClients(valueDate);
|
|
|
|
var dateStr = valueDate.ToString("yyyyMMdd");
|
|
var fileName = $"RH_Otc_Option_List.{dateStr}";
|
|
|
|
var zipFileName = $"{fileName}.zip";
|
|
|
|
var targetPath = Path.Combine("F:");
|
|
if (!Directory.Exists(targetPath))
|
|
{
|
|
targetPath = Path.Combine("D:\\list\\wait", dateStr);
|
|
if (!Directory.Exists(targetPath))
|
|
{
|
|
Directory.CreateDirectory(targetPath);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
targetPath = Path.Combine("F:\\list\\wait", dateStr);
|
|
if (!Directory.Exists(targetPath))
|
|
{
|
|
Directory.CreateDirectory(targetPath);
|
|
}
|
|
}
|
|
|
|
var marketZipFile = Path.Combine(targetPath, zipFileName);
|
|
if (File.Exists(marketZipFile))
|
|
{
|
|
File.Delete(marketZipFile);
|
|
}
|
|
|
|
var excelFileName = $"{fileName}.xlsx";
|
|
var targetFileName = Path.Combine(targetPath, excelFileName);
|
|
var path = Path.Combine(targetPath, targetFileName);
|
|
if (File.Exists(path))
|
|
{
|
|
File.Delete(path);
|
|
}
|
|
|
|
var modelDict = new Dictionary<string, object>();
|
|
if (eods != null)
|
|
{
|
|
modelDict.Add("存续交易", eods);
|
|
}
|
|
if (clients != null)
|
|
{
|
|
modelDict.Add("客户信息", clients);
|
|
}
|
|
|
|
var sourcePath = OtcAppContext.MapPath("~/App_Docs/导出模板");
|
|
var sourceFileName = Path.Combine(sourcePath, "东证RH_Otc_Option_List.xlsx");
|
|
var pdffile = ExcelTemplate.GeneratePDFFromExeclTemplate(sourcePath, sourceFileName, modelDict, targetPath, targetFileName, shouldDeleteSheet: true, needToPdf: false);
|
|
ZipHelper.zipOnlyFile(pdffile, marketZipFile, "Dzrh@2022");
|
|
File.Delete(targetFileName);
|
|
}
|
|
|
|
private List<eod_position_dz> GetEodPosition(DateTime valueDate)
|
|
{
|
|
using (var basedb = new ErpBaseContext())
|
|
{
|
|
EodPriceProvider eodPrice = new EodPriceProvider(valueDate, isDiviendPrice: false);
|
|
eodPrice.Initialize();
|
|
double riskFreeRate = (valuedateBLL.SystemDate.RiskFreeRate / 100).Normalize();
|
|
IEodVolProvider eodVolProvider = EodVolProviderFactory.GetEodVolProvider(valueDate, "持仓");
|
|
List<trade> otcTrades = OtcTrades(valueDate);
|
|
|
|
var eodTradeQuery = DbContext.eod_trade.Where(et => et.ValueDate == valueDate && et.TradeId > 0 && et.TradeType != "结构化交易" && et.ClientId > 0 && ConsTrade.NeedMarginTradeStatusList.Contains(et.TradeStatus));
|
|
|
|
var query = from trade in eodTradeQuery
|
|
join tradeOrigin in DbContext.trade on trade.TradeId equals tradeOrigin.id
|
|
join po in DbContext.eod_trade_position.Where(x => x.ValueDate == valueDate) on trade.TradeId equals po.TradeId into position
|
|
from po in position.DefaultIfEmpty()
|
|
where (tradeOrigin.TradeType != "结构化交易" && tradeOrigin.IsGroup != 1 || tradeOrigin.IsGroup == 1 && tradeOrigin.TradeType == "结构化交易")
|
|
&& (tradeOrigin.IsGroup != 2 || tradeOrigin.IsGroup == 2 && tradeOrigin.TradeType == "收益互换")
|
|
&& tradeOrigin.ValidState != ConsGlobal.InValid
|
|
select new eod_position_dz
|
|
{
|
|
TradeId = tradeOrigin.id,
|
|
TradeType = tradeOrigin.IsGroup == 1 ? tradeOrigin.StructureType : tradeOrigin.TradeType,
|
|
ClientId = tradeOrigin.ClientId,
|
|
TradeNumber = tradeOrigin.TradeNumber,
|
|
TradeDate = tradeOrigin.TradeDate,
|
|
ExerciseDate = tradeOrigin.ExerciseDate,
|
|
PrincipalRate = tradeOrigin.PrincipalRate ?? 0,
|
|
BasisUnderlyingCode = tradeOrigin.BasisUnderlyingCode,
|
|
BasisGap = tradeOrigin.BasisGap ?? 0,
|
|
Lots = tradeOrigin.Lots ?? 0,
|
|
ParticipationRate = tradeOrigin.ParticipationRate ?? 0,
|
|
NoRiskRate = tradeOrigin.NoRiskRate ?? 0,
|
|
UnderlyingCode = trade.UnderlyingCode,
|
|
UnderlyingPrice = null,
|
|
ValueDate = valueDate,
|
|
TradeJson = trade.TradeJson,
|
|
PvDouble = 0,
|
|
PnlDouble = 0,
|
|
InstrumentType = tradeOrigin.UnderlyingInstrumentType,
|
|
IsGroup = tradeOrigin.IsGroup,
|
|
SettlementType = tradeOrigin.SettlementType,
|
|
Margin = po == null ? 0 : po.Margin,
|
|
Pv = po == null ? 0 : PS.Config.IsPVRounded ? po.RoundedPv : po.Pv,
|
|
};
|
|
|
|
var queryList = query.ToList();
|
|
|
|
var underlyingDataSource = DataCacheProvider.GetUnderlyingDataSource();
|
|
var varietyDataSource = DataCacheProvider.GetVarietyDataSource();
|
|
var clients = DataCacheProvider.GetClientDataSource();
|
|
|
|
var varietyTypeList = (from i in basedb.DictionaryItems join d in basedb.Dictionaries on i.DictId equals d.Id where d.Name == "品种类型" select i).ToList();
|
|
var assetTypeList = (from i in basedb.DictionaryItems join d in basedb.Dictionaries on i.DictId equals d.Id where d.Name == "资产类型" select i).ToList();
|
|
GetUpDownLimitPrices(otcTrades, eodPrice, out IPriceProvider upLimitPrices, out IPriceProvider downLimitPrices);
|
|
|
|
foreach (var x in queryList)
|
|
{
|
|
var um = underlyingDataSource.GetData(x.UnderlyingCode);
|
|
|
|
if (um != null)
|
|
{
|
|
if (um.IsSynthetic())
|
|
{
|
|
var sy = underlyingDataSource.GetSyntheticUnderlying(x.UnderlyingCode);
|
|
if (sy != null)
|
|
{
|
|
x.SyntheticUnderlyingTipsInfo = sy.UnderlyingTipsInfo;
|
|
}
|
|
}
|
|
var va = varietyDataSource.GetData(um.UnderlyingTypeId);
|
|
if (va != null)
|
|
{
|
|
x.underingName = um.MarketCode != null ? va.VarietyCode + "." + um.MarketCode : va.VarietyCode;
|
|
x.varietyType = formatDictItem(varietyTypeList, va.AssetType);
|
|
x.assType = formatDictItem(assetTypeList, va.AssetType, "O");
|
|
}
|
|
}
|
|
|
|
if (x.TradeType == "收益互换")
|
|
{
|
|
x.toolType = "SW";
|
|
}
|
|
else if (x.TradeType == "远期" || x.TradeType == "掉期")
|
|
{
|
|
x.toolType = "FW";
|
|
}
|
|
else
|
|
{
|
|
x.toolType = "OP";
|
|
}
|
|
|
|
if (eodPrice.TryGetPrice(x.UnderlyingCode, x.SettlementType, out var price))
|
|
{
|
|
x.UnderlyingPrice = price;
|
|
}
|
|
|
|
var client = clients.GetData(x.ClientId ?? 0);
|
|
if (client != null)
|
|
{
|
|
x.ClientName = client.Name;
|
|
x.clientNumber = client.Number;
|
|
x.ClientType = client.CustomerNature2 != null && !client.CustomerNature2.Contains("产业客户") ? "其他客户" : "产业客户";
|
|
//增加内部客户属性 进行赋值
|
|
x.IsInsided = client.IsInsided;
|
|
}
|
|
|
|
x.dic = x.trade.MetaDic;
|
|
|
|
if (x.TradeType == "现金流交易")
|
|
{
|
|
x.trade.OriginalNotional = null;
|
|
}
|
|
|
|
x.buyType = x.BuySell == "买入" ? "买" : "卖";
|
|
x.isEnd = "否";
|
|
x.tradeType2 = x.OptionType == "看涨" ? "C" : x.OptionType == "看跌" ? "P" : "0";
|
|
|
|
var td = otcTrades.FirstOrDefault(t => t.id == x.TradeId);
|
|
if (td.TradeType != "自定义交易")
|
|
{
|
|
var upValue = CalcLiveOtcTradeValueR(valueDate, td, upLimitPrices, eodVolProvider, riskFreeRate);
|
|
var downValue = CalcLiveOtcTradeValueR(valueDate, td, downLimitPrices, eodVolProvider, riskFreeRate);
|
|
x.MaximumLoss = Math.Min(PS.Config.IsPVRounded ? upValue.RoundedPv : upValue.Pv, PS.Config.IsPVRounded ? downValue.RoundedPv : downValue.Pv) + x.TradePrice;
|
|
}
|
|
}
|
|
//去除内部客户交易
|
|
queryList = queryList.Where(l => l.IsInsided != 1).ToList();
|
|
return queryList;
|
|
}
|
|
}
|
|
|
|
private List<client_dz> GetClients(DateTime valueDate, IEnumerable<int> clienIds = null)
|
|
{
|
|
using (var baseDb = new ClientDBContext())
|
|
{
|
|
var clientQuery = from client in baseDb.client.Where(n => n.ProcessStatus == "已开户" && n.IsInsided != 1)
|
|
select new client_dz
|
|
{
|
|
id = client.id,
|
|
ProtocolSignDate = client.ProtocolSignDate,
|
|
LicenseCode = client.LicenseCode,
|
|
Number = client.Number,
|
|
Name = client.Name,
|
|
ClientType = client.CustomerNature2
|
|
};
|
|
|
|
var creditList = DbContext.credit.Where(t => t.ProcessStatus == "已审批" && (!t.CreditDeadLine.HasValue || t.CreditDeadLine >= valueDate) && (!t.CreditStartDate.HasValue || t.CreditStartDate <= valueDate));
|
|
|
|
if (clienIds != null)
|
|
{
|
|
clientQuery = clientQuery.Where(t => clienIds.Contains(t.id));
|
|
}
|
|
|
|
var list = clientQuery.ToList();
|
|
|
|
foreach (var item in list)
|
|
{
|
|
item.ClientType = item.ClientType != null && !item.ClientType.Contains("产业客户") ? "其他客户" : "产业客户";
|
|
var credit = creditList?.FirstOrDefault(x => x.ClientId == item.id);
|
|
item.isCredit = credit != null ? "是" : "否";
|
|
item.CreditNumber = credit != null ? credit.Credit : null;
|
|
}
|
|
|
|
return list;
|
|
}
|
|
}
|
|
|
|
private static string formatDictItem(List<DictionaryItem> dictItemMap, string name, string defaultValue = "")
|
|
{
|
|
if (name == null || dictItemMap == null) { return defaultValue; }
|
|
var obj = dictItemMap.FirstOrDefault(O => O.Name == name);
|
|
return obj == null ? defaultValue : obj.ShortName;
|
|
}
|
|
|
|
private TradeValueResult CalcLiveOtcTradeValueR(DateTime valueDate, trade td, IPriceProvider eodPrice, IEodVolProvider volProvider, double riskFreeRate)
|
|
{
|
|
var underlyings = new underlying_manager[] { new underlying_manager { UnderlyingCode = td.UnderlyingCode } };
|
|
|
|
var spotPrice = eodPrice.GetPrice(td.UnderlyingCode);
|
|
|
|
switch (td.TradeType)
|
|
{
|
|
case ConsGlobal.TradeType.Forward:
|
|
{
|
|
if (PS.Config.ErpElement.ForwardTradePriceModel == Configuration.Enums.ForwardTradePriceModel.STANDARD && !string.IsNullOrWhiteSpace(td.BasisUnderlyingCode))
|
|
{
|
|
var BasiseodPrice = eodPrice.GetPrice(td.BasisUnderlyingCode);
|
|
spotPrice -= BasiseodPrice;
|
|
}
|
|
return ForwardradeCalcService.CalcValue(td, spotPrice);
|
|
}
|
|
case ConsGlobal.TradeType.PayoffSwap:
|
|
return PayoffSwapCalcService.CalcValue(td, valueDate, eodPrice, true);
|
|
default:
|
|
{
|
|
var req = new OptionValueCalcRequest(riskFreeRate)
|
|
{
|
|
correlations = null,//不计算彩虹等多标的期权暂时不需要
|
|
engineName = null,
|
|
preciseTimeMode = false, //日终一定是false
|
|
isEodCalc = true,
|
|
pricingRequest = QdpPricingRequest.BASIC_GREEKS,
|
|
spotPrices = new[] { spotPrice },
|
|
calcScenario = Enums.CalcScenarioEnum.EodSettlement,
|
|
};
|
|
if (td.TradeType != ConsGlobal.TradeType.CashFlow)
|
|
{
|
|
var vol = volProvider.GetVol(td, spotPrice) ?? ConsGlobal.DefaultVol;
|
|
|
|
req.vols = new[] { vol };
|
|
}
|
|
return OptionCalculatorV2.GetOptionValueResult(valueDate, td, req, out underlyings);
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 获取涨跌20%停价格字典
|
|
/// </summary>
|
|
private void GetUpDownLimitPrices(List<trade> trade, EodPriceProvider eodPrice, out IPriceProvider upLimitPrices, out IPriceProvider downLimitPrices)
|
|
{
|
|
HashSet<string> _underlyingCodeSet;
|
|
|
|
_underlyingCodeSet = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
|
|
|
|
void setUnderlyingCode(trade td)
|
|
{
|
|
if (td?.UnderlyingCode == null)
|
|
{
|
|
return;
|
|
}
|
|
_underlyingCodeSet.Add(td.UnderlyingCode);
|
|
switch (td.TradeType)
|
|
{
|
|
case "彩虹期权":
|
|
if (td.trade_rainbow_option != null)
|
|
{
|
|
_underlyingCodeSet.Add(td.trade_rainbow_option.UnderlyingAssetCode2);
|
|
}
|
|
break;
|
|
case "价差期权":
|
|
if (td.trade_spread_option != null)
|
|
{
|
|
var codes = td.trade_spread_option.UnderlyingAssetCodes();
|
|
foreach (var code in codes)
|
|
{
|
|
_underlyingCodeSet.Add(code);
|
|
}
|
|
}
|
|
break;
|
|
case "结构化交易":
|
|
if (td.SubTrades != null)
|
|
{
|
|
foreach (var std in td.SubTrades)
|
|
{
|
|
setUnderlyingCode(std);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
foreach (var td in trade)
|
|
{
|
|
setUnderlyingCode(td);
|
|
}
|
|
|
|
var upLimitPrices2 = new ManualPriceProvider();
|
|
var downLimitPrices2 = new ManualPriceProvider();
|
|
|
|
//根据涨跌幅限制以及当日结算价计算涨停价以及跌停价
|
|
foreach (var code in _underlyingCodeSet)
|
|
{
|
|
if (eodPrice.TryGetPrice(code, SettlementTypeEnum.ClosePrice, out var price))
|
|
{
|
|
var limit = price * 0.2;
|
|
var upprice = price + limit;
|
|
var downprice = price - limit;
|
|
upLimitPrices2.SetPrice(code, upprice);
|
|
downLimitPrices2.SetPrice(code, downprice);
|
|
}
|
|
}
|
|
|
|
upLimitPrices = upLimitPrices2;
|
|
downLimitPrices = downLimitPrices2;
|
|
}
|
|
|
|
TradeCashDataProvider _tradeCashProvider;
|
|
|
|
private List<trade> OtcTrades(DateTime valueDate)
|
|
{
|
|
//如果前一天是假日,要显示包含假日的交易
|
|
var preday = BLL.valuedateBLL.GetNonHolidayDefore(valueDate.AddDays(-1));
|
|
|
|
var predicate = PredicateBuilder.Create<trade>(t => t.TradeDate <= valueDate && t.ValidState != ConsGlobal.InValid && t.ClientId > 0
|
|
&& t.TradeType != "结构化交易" && t.ExerciseDate > preday && (!ConsTrade.TradeCompleteStatus.Contains(t.TradeStatus) || t.UnWindDate > preday));
|
|
|
|
var list = new EodSettleDataQueryService(UserInfo)
|
|
.GetOtcTrades(valueDate, predicate, out _tradeCashProvider);
|
|
|
|
var hisDataProvider = new TradeHisDataProvider(valueDate).Initialize();
|
|
|
|
foreach (var item in list)
|
|
{
|
|
var noRiskRate = hisDataProvider.GetNoRiskRate(item.id);
|
|
var dividendRate = hisDataProvider.GetDividendRate(item.id);
|
|
//如果修改过无风险利率或分红率,且和eodTrade中不匹配,则移除该交易来自EodTrade的标记;
|
|
if (((noRiskRate ?? 0) > 0 && noRiskRate.GetValueOrDefault() != item.NoRiskRate.GetValueOrDefault()) ||
|
|
((dividendRate ?? 0) > 0 && dividendRate.GetValueOrDefault() != item.DividendRate.GetValueOrDefault()))
|
|
{
|
|
item.MetaDic.Remove("from_eod_trade");
|
|
}
|
|
item.NoRiskRate = noRiskRate ?? item.NoRiskRate ?? BLL.valuedateBLL.RiskFreeRate;
|
|
item.DividendRate = dividendRate ?? item.DividendRate;
|
|
if (item.DividendRate == null)
|
|
{
|
|
item.DividendRate = DataCacheProvider.GetUnderlyingDataSource().GetData(item.UnderlyingCode)?.DividendRate ?? item.NoRiskRate;
|
|
}
|
|
}
|
|
|
|
return list;
|
|
}
|
|
}
|
|
|
|
public class eod_position_dz : eod_position
|
|
{
|
|
public string clientNumber { set; get; }
|
|
public string ClientType { get; set; }
|
|
|
|
public string buyType { get; set; }
|
|
public string isEnd { get; set; }
|
|
public string tradeType2 { get; set; }
|
|
public string varietyType { get; set; }
|
|
public string assType { get; set; }
|
|
public string toolType { get; set; }
|
|
public string underingName { get; set; }
|
|
/// <summary>
|
|
/// 最大亏损
|
|
/// </summary>
|
|
public double? MaximumLoss { set; get; }
|
|
/// <summary>
|
|
/// 内部客户
|
|
/// </summary>
|
|
public int? IsInsided { get; set; }
|
|
}
|
|
|
|
public class client_dz
|
|
{
|
|
public int id { get; set; }
|
|
public DateTime? ProtocolSignDate { get; set; }
|
|
public string LicenseCode { get; set; }
|
|
public string Number { set; get; }
|
|
public string Name { set; get; }
|
|
public string ClientType { get; set; }
|
|
public string isCredit { set; get; }
|
|
public double? CreditNumber { set; get; }
|
|
}
|
|
}
|