116 lines
4.3 KiB
C#
116 lines
4.3 KiB
C#
using Qdp.Pricing.Base.Implementations;
|
|
using YLErp.Modules.CalculationModule;
|
|
using YLErp.Modules.EodModule.SettlementModule;
|
|
using YLErp.QdpModule;
|
|
|
|
namespace YLErp.Modules.EodModule
|
|
{
|
|
[TestClass]
|
|
public class EodSettlementTest : UnitTestBase
|
|
{
|
|
[TestMethod("收盘估值计算")]
|
|
public void TestCalcPv()
|
|
{
|
|
var settleDate = new DateTime(2021, 4, 27);
|
|
var predicate = PredicateBuilder.Create<trade>(t => t.TradeNumber == "CW20210016E0002");
|
|
var otcTrades = new EodSettleDataQueryService(GetOptUser())
|
|
.GetOtcTrades(settleDate, predicate, out var tradeCashProvider);
|
|
var td = otcTrades.FirstOrDefault();
|
|
if (td == null)
|
|
{
|
|
Console.WriteLine("没有找到交易");
|
|
return;
|
|
}
|
|
var eodpriceProvider = new YLErp.Modules.DataProviderModule.EodPriceProvider(settleDate);
|
|
var spotPrice = eodpriceProvider.GetPrice(td.UnderlyingCode, SettlementTypeEnum.ClosePrice);
|
|
var req = new OptionValueCalcRequest(td.NoRiskRate ?? 0)
|
|
{
|
|
correlations = null,//不计算彩虹等多标的期权暂时不需要
|
|
engineName = null,
|
|
preciseTimeMode = false, //日终一定是false
|
|
pricingRequest = QdpPricingRequest.BASIC_GREEKS,
|
|
spotPrices = new[] { spotPrice }
|
|
};
|
|
if (td.TradeType != ConsGlobal.TradeType.CashFlow)
|
|
{
|
|
var volProvider = EodVolProviderFactory.GetEodVolProvider(settleDate, "持仓");
|
|
var vol = volProvider.GetVol(td, spotPrice) ?? ConsGlobal.DefaultVol;
|
|
req.vols = new[] { vol };
|
|
}
|
|
var option = OptionCalculatorV2.GetOptionValueResult(settleDate, td, req, out var underlyings);
|
|
Console.WriteLine($"[{td.TradeType},{td.TradeNumber},{td.id}] pv:{option.Pv}, delta:{option.Delta}");
|
|
}
|
|
|
|
[TestMethod("测试盈亏分解--当天新开仓的交易")]
|
|
public void TestCalcPnlExplainV2_NewOtcTradeDeal()
|
|
{
|
|
var db = DbContextFactory.GetYLDbContext();
|
|
|
|
var td = db.trade.FirstOrDefault(n => n.TradeNumber == "CW20210016C0001");
|
|
|
|
YLErp.BLL.tradeBLL.SetFieldsByTradeType(td);
|
|
|
|
var pnl = new EodPnl();
|
|
|
|
double spot0 = 5910, spot1 = 5911, pv1 = 53796.37;
|
|
|
|
var pS0V1Q1T1 = CalcPnlExplainV2(td, new CalcField
|
|
{
|
|
spot = spot0,
|
|
vol = 0.28,
|
|
dividendRate = 0,
|
|
riskFreeRate = 0.03,
|
|
date = new DateTime(2021, 4, 27)
|
|
}, PricingRequest.Pv | PricingRequest.Delta, x =>
|
|
{
|
|
|
|
});
|
|
|
|
if (pS0V1Q1T1 != null)
|
|
{
|
|
pnl.PnLVega += NumberHelper.Normalize(pS0V1Q1T1.Pv - ((td.TradeSinglePrice ?? 0) * td.Notional));
|
|
pnl.PnLDelta += NumberHelper.Normalize(pS0V1Q1T1.Delta * (spot1 - spot0));
|
|
pnl.PnLGamma += NumberHelper.Normalize(pv1 - pS0V1Q1T1.Pv - pnl.PnLDelta);
|
|
Console.WriteLine($"pS0V1Q1T1 pv:{pS0V1Q1T1.Pv}, delta:{pS0V1Q1T1.Delta}");
|
|
}
|
|
Console.WriteLine("计算失败");
|
|
}
|
|
|
|
//计算pv和delta
|
|
private static TradeValueResult CalcPnlExplainV2(trade td, CalcField f, PricingRequest pricingRequest
|
|
, Action<OptionTradeParamBase> paramOverride = null)
|
|
{
|
|
td.NoRiskRate = f.riskFreeRate;
|
|
td.DividendRate = f.dividendRate;
|
|
|
|
var req = new OptionValueCalcRequest(f.riskFreeRate)
|
|
{
|
|
correlations = null,//不计算彩虹等多标的期权暂时不需要
|
|
engineName = null,
|
|
preciseTimeMode = false, //日终一定是false
|
|
pricingRequest = pricingRequest,
|
|
spotPrices = new[] { f.spot },
|
|
vols = new[] { f.vol },
|
|
ParamOverride = paramOverride
|
|
};
|
|
|
|
return OptionCalculatorV2.GetOptionValueResult(f.date, td, req, out _);
|
|
}
|
|
|
|
class CalcField
|
|
{
|
|
//public double pv;
|
|
|
|
public DateTime date;
|
|
|
|
public double vol;
|
|
|
|
public double dividendRate;
|
|
|
|
public double spot;
|
|
|
|
public double riskFreeRate;
|
|
}
|
|
}
|
|
}
|