363 lines
18 KiB
C#
363 lines
18 KiB
C#
using YLErp.Modules.CalculationModule;
|
|
|
|
namespace YLErp.Modules.EodModule.SettlementModule
|
|
{
|
|
/// <summary>
|
|
/// 方顿日终数据接口服务
|
|
/// </summary>
|
|
public class FangDunSettlementService : YLBaseService
|
|
{
|
|
public FangDunSettlementService(OptUserInfo userInfo) : base(userInfo)
|
|
{
|
|
|
|
}
|
|
|
|
/// <summary>
|
|
/// 获取方顿日终数据1
|
|
/// </summary>
|
|
public List<ResponseTrade> GetEodData1(FangDunEodData1Request req)
|
|
{
|
|
var handleTrades = (from tp in DbContext.eod_trade_position.Where(l => l.ValueDate == req.ValueDate && l.TradeId > 0)
|
|
join tr in DbContext.eod_trade_risk.Where(l => l.ValueDate == req.ValueDate) on tp.TradeId equals tr.TradeId
|
|
join x in DbContext.trade.Where(t => t.ValidState != "InValid" && (t.TradeType != "结构化交易" || t.IsGroup == 1) && t.IsGroup != 2) on tp.TradeId equals x.id
|
|
join tbo in DbContext.trade_barrier_option on tp.TradeId equals tbo.TradeId
|
|
into tbo
|
|
from tbo2 in tbo.DefaultIfEmpty()
|
|
join tao in DbContext.trade_asian_option on tp.TradeId equals tao.TradeId
|
|
into tao
|
|
from tao2 in tao.DefaultIfEmpty()
|
|
join ta in DbContext.trade_autocall on tp.TradeId equals ta.TradeId
|
|
into ta
|
|
from ta2 in ta.DefaultIfEmpty()
|
|
join ts in DbContext.trade_snowball on tp.TradeId equals ts.TradeId
|
|
into ts
|
|
from ts2 in ts.DefaultIfEmpty()
|
|
select new HandleTrade
|
|
{
|
|
tradeModel = x,
|
|
trade_Asian_Option = tao2,
|
|
TraderId = tp.TradeId,
|
|
UnderlyingCode = tp.UnderlyingCode,
|
|
TradeType = tp.TradeType,
|
|
ordid = x.ParentTradeId == 0 ? x.TradeNumber : DbContext.trade.FirstOrDefault(c => (c.id == x.ParentTradeId && c.TradeType == "结构化交易")).TradeNumber,
|
|
groupid = "10038801",
|
|
sub_ordid = x.ParentTradeId == 0 ? "0" : x.TradeNumber.Substring(x.TradeNumber.IndexOf("-") + 1),
|
|
effective_date_from = x.TradeDate,
|
|
effective_date_to = x.ExerciseDate,
|
|
ClientId = x.ClientId,
|
|
ordname = tp.UnderlyingCode + "-" + (x.OptionType == "看涨" ? "Call" : "Put"),
|
|
contract_type_cls = x.TradeType,
|
|
long_short_position_cls = x.BuySell == "买入" ? "L" : "S",
|
|
put_call_cls = x.OptionType == "看涨" ? "C" : "P",
|
|
settlement_type_cls = "C",
|
|
exercise_type_cls = x.ExerciseMode == "European" ? "1" : "2",
|
|
strike_price = x.Strike,
|
|
settlement_currency = "CNY",
|
|
pricing_currency = "CNY",
|
|
start_date = x.TradeDate,
|
|
maturity_date = x.ExerciseDate,
|
|
premium_amt = x.TradePrice,
|
|
premium_date = x.PremiumPayDate,
|
|
participation_rate = x.ParticipationRate,
|
|
levelpercentage = 0,
|
|
calendar_type_cls = "2",
|
|
counterparty_name = x.ClientName,
|
|
businessday_convention_cls = "2",
|
|
calcrules_cls = "4",
|
|
single_multi_cls = "1",
|
|
weight_calc_cls = "1",
|
|
additionalproduct_type = x.TradeType == "香草期权" ? "普通期权" : "奇异期权",
|
|
dis_rate = x.DividendRate,
|
|
underlying_stkcode = tp.UnderlyingCode,
|
|
caihua_setype0_cls = "5",
|
|
initial_spot = x.SpotPrice,
|
|
weight_rate = 1,
|
|
div_rate = x.DividendRate,
|
|
vol_rate = tr.Vol,
|
|
fund_rate = x.DividendRate,
|
|
barrierType = tbo2.BarrierType,
|
|
barrier_value = tbo2.BarrierPrice,
|
|
rebate_rate = tbo2.Rebate,
|
|
IsMoneynessOption = x.IsMoneynessOption,
|
|
KOBarrier = ta2.KOBarrier,
|
|
KIBarrier = ta2.KIBarrier,
|
|
coupon_rate = ts2.KORebate,
|
|
observationdate_list = x.ObservationDateStr,
|
|
obsfreq = "每日",//todo 每日
|
|
PayoffType = tao2.PayoffType,
|
|
notional = tp.Amount * x.SpotPrice,
|
|
margin = x.MarginRate,
|
|
float_profit_loss = tp.PositionPnL,
|
|
accu_profit_loss = tp.ClosedPnL,
|
|
npv = tp.Pv,
|
|
delta = tr.Delta,
|
|
gamma = tr.Gamma,
|
|
theta = tr.Theta,
|
|
vega = tr.Vega,
|
|
rho = tr.Rho * 100,
|
|
settle_date = x.SettlementDate.ToString(),
|
|
volume = tp.Amount,
|
|
cashdelta = tr.DeltaCash,
|
|
current_value = (x.TradeSinglePrice),
|
|
market_value = (tp.Amount * x.TradeSinglePrice) ?? 0,
|
|
pnl = tp.DailyPnL,
|
|
stress_test_value = (tr.DeltaCash * 21.68 / 100 + tr.Vega * 0.1),// 单退
|
|
underlying_stk_qty = tp.Amount,
|
|
underlying_royalty_price = x.TradeSinglePrice,
|
|
}).ToList();
|
|
var responseTrade = HanderlResponseTradeData(req.ValueDate, handleTrades);
|
|
return responseTrade;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 转换成Response
|
|
/// </summary>
|
|
private List<ResponseTrade> HanderlResponseTradeData(DateTime valueDate, List<HandleTrade> handleTrades)
|
|
{
|
|
var responseTrades = new List<ResponseTrade>();
|
|
foreach (var item in handleTrades)
|
|
{
|
|
var responseTrade = new ResponseTrade();
|
|
responseTrade.ordid = item.ordid;
|
|
responseTrade.groupid = item.groupid;
|
|
responseTrade.sub_ordid = item.sub_ordid;
|
|
responseTrade.sac_ordid = item.sac_ordid;
|
|
responseTrade.contract_type_cls = GetTradeTypeAbbreviation(item);
|
|
responseTrade.long_short_position_cls = item.long_short_position_cls;
|
|
responseTrade.put_call_cls = item.put_call_cls;
|
|
responseTrade.settlement_type_cls = item.settlement_type_cls;
|
|
responseTrade.exercise_type_cls = item.exercise_type_cls;
|
|
responseTrade.strike_price = item.strike_price;
|
|
responseTrade.settlement_currency = item.settlement_currency;
|
|
responseTrade.pricing_currency = item.pricing_currency;
|
|
responseTrade.premium_amt = item.premium_amt;
|
|
responseTrade.participation_rate = item.participation_rate;
|
|
responseTrade.levelpercentage = item.levelpercentage;
|
|
responseTrade.calendar_type_cls = item.calendar_type_cls;
|
|
responseTrade.counterparty_name = item.counterparty_name;
|
|
responseTrade.counterparty_sac_ordid = item.counterparty_sac_ordid;
|
|
responseTrade.businessday_convention_cls = item.businessday_convention_cls;
|
|
responseTrade.calcrules_cls = item.calcrules_cls;
|
|
responseTrade.single_multi_cls = item.single_multi_cls;
|
|
responseTrade.weight_calc_cls = item.weight_calc_cls;
|
|
responseTrade.additionalproduct_type = item.additionalproduct_type;
|
|
responseTrade.dis_rate = item.dis_rate;
|
|
responseTrade.underlying_stkcode = item.underlying_stkcode;
|
|
responseTrade.underlying_caihua_trade_market = GetUnderlyingCaihuaTradeMarket(item.underlying_caihua_trade_market);
|
|
responseTrade.caihua_setype0_cls = item.caihua_setype0_cls;
|
|
responseTrade.initial_spot = item.initial_spot;
|
|
responseTrade.weight_rate = item.weight_rate;
|
|
responseTrade.div_rate = item.div_rate;
|
|
responseTrade.vol_rate = item.vol_rate;
|
|
responseTrade.fund_rate = item.fund_rate;
|
|
responseTrade.barrier_type_cls = item.barrier_type_cls;
|
|
responseTrade.barrier_value = item.barrier_value;
|
|
responseTrade.rebate_rate = item.rebate_rate;
|
|
responseTrade.knockout_price = item.knockout_price;
|
|
responseTrade.knockin_price = item.knockin_price;
|
|
responseTrade.coupon_rate = item.coupon_rate;
|
|
responseTrade.observationdate_list = item.observationdate_list;
|
|
responseTrade.observe_start_date = item.observe_start_date;
|
|
responseTrade.observe_end_date = item.observe_end_date;
|
|
responseTrade.obsfreq = item.obsfreq;
|
|
responseTrade.avg_type_cls = item.avg_type_cls;
|
|
responseTrade.discrete_type_cls = item.discrete_type_cls;
|
|
responseTrade.notional = item.notional;
|
|
responseTrade.margin = item.margin;
|
|
|
|
var nowPrice = item.cashdelta / item.delta;
|
|
|
|
//亚试
|
|
responseTrade.accu_underlying_price_asian = AsianOptionCalcHelper.GetAveragePrice(item.tradeModel, item.trade_Asian_Option, nowPrice, valueDate, out var fixingsCount);
|
|
|
|
responseTrade.accu_past_count_asian = fixingsCount;
|
|
responseTrade.float_profit_loss = item.float_profit_loss;
|
|
responseTrade.accu_profit_loss = item.accu_profit_loss;
|
|
responseTrade.npv = item.npv;
|
|
responseTrade.delta = item.delta;
|
|
responseTrade.gamma = item.gamma;
|
|
responseTrade.theta = item.theta;
|
|
responseTrade.vega = item.vega;
|
|
responseTrade.rho = item.rho;
|
|
responseTrade.settle_date = item.settle_date;
|
|
responseTrade.product_code = item.product_code;
|
|
responseTrade.volume = item.volume;
|
|
responseTrade.cashdelta = item.cashdelta;
|
|
responseTrade.current_value = item.current_value;
|
|
responseTrade.market_value = item.market_value;
|
|
responseTrade.pnl = item.pnl;
|
|
using (var db = DbContextFactory.GetYLDbContext())
|
|
{
|
|
//多退
|
|
if (db.trade.Any(t => t.ParentTradeId == item.tradeModel.id))
|
|
{
|
|
var ids = db.trade.Where(t => t.ParentTradeId == item.tradeModel.id).Select(l => l.id).ToArray();
|
|
var list = db.eod_trade_risk.Where(t => ids.Contains(t.TradeId)).Select(l => new { l.Vega, l.DeltaCash });
|
|
double vega = 0;
|
|
double deltaCash = 0;
|
|
list.ForEachAsync(t => { vega += t.Vega; deltaCash += t.DeltaCash; });
|
|
responseTrade.stress_test_value = (deltaCash * 21.68 / 100 + vega * 0.1);
|
|
}
|
|
else
|
|
{
|
|
responseTrade.stress_test_value = item.stress_test_value;
|
|
}
|
|
}
|
|
|
|
responseTrade.underlying_stk_qty = item.underlying_stk_qty;
|
|
responseTrade.underlying_multiplier = item.underlying_multiplier;
|
|
responseTrade.underlying_royalty_price = item.underlying_royalty_price;
|
|
responseTrade.effective_date_from = ConvertDateToInt(item.effective_date_from);
|
|
responseTrade.effective_date_to = ConvertDateToInt(item.effective_date_to);
|
|
responseTrade.maturity_date = ConvertDateToInt(item.maturity_date);
|
|
responseTrade.premium_date = ConvertDateToInt(item.premium_date);
|
|
responseTrade.start_date = ConvertDateToInt(item.start_date);
|
|
responseTrade.ordname = item.ordname + "-" + Convert.ToDateTime(item.tradeModel.ExerciseDate).ToString("MMdd") + "M-" + item.tradeModel.Strike + "K" + (item.trade_Asian_Option != null ? ("-" + (Convert.ToDateTime(item.trade_Asian_Option?.AveragingPeriodStartDate).ToString("MMdd") ?? Convert.ToDateTime(item.effective_date_from).ToString("MMdd"))) + "OB" : "");
|
|
|
|
DoubleIsNan(responseTrade);
|
|
responseTrades.Add(responseTrade);
|
|
}
|
|
return responseTrades;
|
|
}
|
|
|
|
private void DoubleIsNan(ResponseTrade rt)
|
|
{
|
|
|
|
var t = rt.GetType();
|
|
foreach (System.Reflection.PropertyInfo p in rt.GetType().GetProperties())
|
|
{
|
|
if (p.PropertyType.IsValueType && p.PropertyType.FullName.Contains("Double"))
|
|
{
|
|
if (p.GetValue(rt) != null)
|
|
{
|
|
if (p.GetValue(rt)?.ToString() == "NAN" || !((Double)p.GetValue(rt)).IsNormalize())
|
|
{
|
|
p.SetValue(rt, null);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
public string GetUnderlyingCaihuaTradeMarket(string TradeMarketName)
|
|
{
|
|
var strCode = "";
|
|
switch (TradeMarketName)
|
|
{
|
|
case "上海证券交易所":
|
|
strCode = "001002";
|
|
break;
|
|
case "深圳证券交易所":
|
|
strCode = "001003";
|
|
break;
|
|
case "上海期货交易所":
|
|
strCode = "001008";
|
|
break;
|
|
case "上海国际能源交易所":
|
|
strCode = "001061";
|
|
break;
|
|
case "上海黄金交易所":
|
|
strCode = "001015";
|
|
break;
|
|
case "中国金融期货交易所":
|
|
strCode = "001009";
|
|
break;
|
|
case "郑州商品交易所":
|
|
strCode = "001017";
|
|
break;
|
|
case "大连商品交易所":
|
|
strCode = "001016";
|
|
break;
|
|
}
|
|
return strCode;
|
|
}
|
|
/// <summary>
|
|
/// 交易类型 转换简称
|
|
/// </summary>
|
|
/// <param name="t"></param>
|
|
/// <returns></returns>
|
|
public string GetTradeTypeAbbreviation(HandleTrade ht)
|
|
{
|
|
var strType = "";
|
|
switch (ht.tradeModel.TradeType)
|
|
{
|
|
case "香草期权":
|
|
strType = "VNL";
|
|
break;
|
|
case "障碍期权":
|
|
//if (t.trade_barrier_option.BarrierType.Contains("双障碍敲"))
|
|
//{
|
|
// //二元障碍期权
|
|
// strType = "BIB";
|
|
//}
|
|
//else
|
|
//{
|
|
strType = "BRR";
|
|
//}
|
|
break;
|
|
case "多触碰点障碍期权": //todo
|
|
strType = "ACL";
|
|
break;
|
|
case "亚式期权":
|
|
var type = ht.PayoffType ?? "";
|
|
if (type.Contains("Enhanced"))
|
|
{
|
|
strType = "ESA";//增强亚式
|
|
}
|
|
else
|
|
{
|
|
strType = "ASN";//亚式
|
|
}
|
|
break;
|
|
case "二元期权":
|
|
if (ht.tradeModel.ExerciseMode == "European")
|
|
{
|
|
strType = "DGT";
|
|
}
|
|
else
|
|
{
|
|
//一触即发期权
|
|
strType = "TRN";
|
|
}
|
|
break;
|
|
case "结构化交易":
|
|
strType = "STG";
|
|
break;
|
|
case "凤凰期权":
|
|
strType = "PHX";
|
|
break;
|
|
case "雪球期权":
|
|
strType = "SNB";
|
|
break;
|
|
|
|
case "区间累计期权":
|
|
strType = "RAL";
|
|
break;
|
|
default:
|
|
strType = "UNK";
|
|
break;
|
|
}
|
|
return strType;
|
|
|
|
}
|
|
/// <summary>
|
|
/// 日期转换int
|
|
/// </summary>
|
|
private static int ConvertDateToInt(DateTime? dt)
|
|
{
|
|
if (dt == null) return 0;
|
|
|
|
return dt.Value.Year * 10000 + dt.Value.Month * 100 + dt.Value.Day;
|
|
}
|
|
|
|
}
|
|
|
|
/// <summary>
|
|
/// 方顿日终数据接口1请求
|
|
/// </summary>
|
|
public class FangDunEodData1Request
|
|
{
|
|
public DateTime ValueDate { get; set; }
|
|
}
|
|
}
|