262 lines
11 KiB
C#
262 lines
11 KiB
C#
using YLErp.BLL;
|
|
using YLErp.Commons;
|
|
using YLErp.Configuration;
|
|
using YLErp.Enums;
|
|
using YLErp.Modules.CalculationModule;
|
|
using YLErp.Modules.DataProviderModule;
|
|
using YLErp.Modules.StructureModule;
|
|
|
|
namespace YLErp.Modules.ApiModule
|
|
{
|
|
public static class TradeCalcApiHelper
|
|
{
|
|
static readonly HttpClientWrap _httpClientWrap;
|
|
|
|
public const string PV = "pv";
|
|
public const string DELTA = "delta";
|
|
public const string GAMMA = "gamma";
|
|
public const string VEGA = "vega";
|
|
public const string RHO = "rho";
|
|
public const string THETA = "theta";
|
|
public const string MARGIN = "margin";
|
|
|
|
static TradeCalcApiHelper()
|
|
{
|
|
_httpClientWrap = new HttpClientWrap(PS.Config.ErpElement.ExternalAPIForCustomCalc, PS.Config.ErpElement.ExternalAPIForCustomCalcTimeOut);
|
|
}
|
|
|
|
public static string PostJson(string apiPath, object postData)
|
|
{
|
|
if (_httpClientWrap.BaseAddress == null)
|
|
{
|
|
throw new ServiceException("ExternalAPI未配置");
|
|
}
|
|
|
|
try
|
|
{
|
|
return _httpClientWrap.PostJson(apiPath, postData, null);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
LogFactory.GetLogger("ExternalAPI-Post").Error(apiPath, ex);
|
|
throw;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 调用外部接口计算自定义交易
|
|
/// </summary>
|
|
/// <param name="valueDate">估值日期</param>
|
|
/// <param name="t">交易信息</param>
|
|
/// <param name="spotPrice">价格</param>
|
|
/// <param name="isSettle">是否结算,会影响结算时无风险利率和分红率是否需要从历史记录中取</param>
|
|
/// <param name="calcMethod">要计算的要素</param>
|
|
/// <returns></returns>
|
|
public static ReturnInfo<TradeValueResult> CalculateCustomizedTrade(DateTime valueDate, trade t
|
|
, double spotPrice, double volValue, bool isSettle, CalcScenarioEnum calcScenario, params string[] calcMethod)
|
|
{
|
|
if (t is null)
|
|
{
|
|
throw new ArgumentNullException(nameof(t));
|
|
}
|
|
if (t.TradeType != "自定义交易")
|
|
{
|
|
throw new Exception("只支持自定义交易计算");
|
|
}
|
|
if (PS.Config.Company == CompanyEnum.广期资本 && !(t.StructureType.StartsWith("API-")))
|
|
{
|
|
TempValueResult temp=new TempValueResult();
|
|
var r = Return.Success<TradeValueResult>(temp, "");
|
|
r.Content.Pv = 0;
|
|
r.Content.Delta = 0;
|
|
r.Content.Gamma = 0;
|
|
r.Content.Vega = 0;
|
|
r.Content.CalendarDayTheta = 0;
|
|
r.Content.TradingDayTheta = 0;
|
|
r.Content.Rho = 0;
|
|
r.Content.DeltaCash = 0;
|
|
r.Content.GammaCash = 0;
|
|
r.Content.VegaCash = 0;
|
|
r.Content.Rho = 0;
|
|
return r;
|
|
}
|
|
|
|
var umInfo = DataCacheProvider.GetUnderlyingDataSource().GetData(t.UnderlyingCode ?? "");
|
|
var varietyInfo = DataCacheProvider.GetVarietyDataSource().GetData(umInfo?.UnderlyingTypeId ?? 0);
|
|
var service = new TradeHisDataProvider(valueDate);
|
|
var noRiskRate = service.GetNoRiskRate(t.id);
|
|
var dividendRate = service.GetDividendRate(t.id);
|
|
if (!isSettle || !noRiskRate.HasValue)
|
|
{
|
|
noRiskRate = t.NoRiskRate ?? valuedateBLL.SysRiskFreeRate();
|
|
dividendRate = t.DividendRate;
|
|
}
|
|
var structureList = new StructureService(OptUserInfo.SystemUser).QueryStructure_Details(t.StructureType);
|
|
var extendInfo = new Dictionary<string, object>();
|
|
foreach (var item in t.Propertys)
|
|
{
|
|
var columnType = structureList.Where(O => O.ColumnName == item.name).Select(O => O.ColumnType).FirstOrDefault();
|
|
switch (columnType)
|
|
{
|
|
case StructureColumnTypeEnum.NUMBER:
|
|
if (double.TryParse(item.value, out var value))
|
|
{
|
|
extendInfo[item.name] = value;
|
|
}
|
|
else
|
|
{
|
|
throw new ServiceException($"{t.TradeNumber}交易中 {item.name} 字段值:{item.value} 无法转换为数值类型");
|
|
}
|
|
break;
|
|
case StructureColumnTypeEnum.DATE:
|
|
if (DateTime.TryParse(item.value, out var date))
|
|
{
|
|
extendInfo[item.name] = date;
|
|
}
|
|
else
|
|
{
|
|
throw new ServiceException($"{t.TradeNumber}交易中 {item.name} 字段值{item.value} 无法转换为日期类型");
|
|
}
|
|
break;
|
|
case StructureColumnTypeEnum.TEXT:
|
|
case StructureColumnTypeEnum.COMBO_BOX_SINGLE:
|
|
default:
|
|
extendInfo[item.name] = item.value;
|
|
break;
|
|
}
|
|
}
|
|
|
|
var postData = new Dictionary<string, object>
|
|
{
|
|
["CalcId"] = string.IsNullOrWhiteSpace(t.TradeNumber) ? Guid.NewGuid().ToString("N") : t.TradeNumber,
|
|
["ValueDate"] = valueDate.ToString("yyyy-MM-dd"),
|
|
["CalcMethods"] = calcMethod,
|
|
["StructureType"] = t.StructureType ?? "",
|
|
["CallPut"] = t.CallPut,
|
|
["StartDate"] = t.StartDate,
|
|
["ExerciseDate"] = t.ExerciseDate,
|
|
["BuySell"] = "买入",
|
|
["InitialSpotPrice"] = t.SpotPrice,
|
|
["Strike"] = t.IsMoneynessOptionData ? t.Strike * t.SpotPrice : t.Strike,
|
|
["UnderlyingCode"] = t.UnderlyingCode,
|
|
["UnderlyingPrice"] = spotPrice,
|
|
["RiskFreeRate"] = noRiskRate,
|
|
["DividendRate"] = dividendRate,
|
|
["UpDownLimit"] = NumberHelper.TryParse(umInfo?.UpDownLimit, out var pval, out var isPercent) ? pval : varietyInfo?.UpLimitValue ?? 0,
|
|
["Volatility"] = volValue
|
|
};
|
|
|
|
var baseInfo = t.Clone();
|
|
TradeHelper2.ReduceTradeExt(baseInfo);
|
|
|
|
baseInfo.CalcId = null;
|
|
baseInfo.StructureType = null;
|
|
baseInfo.OptionType = null;
|
|
baseInfo.StartDate = null;
|
|
baseInfo.ExerciseDate = null;
|
|
baseInfo.BuySell = null;
|
|
baseInfo.InitialSpotPrice = null;
|
|
baseInfo.Strike = null;
|
|
baseInfo.UnderlyingCode = null;
|
|
baseInfo.UnderlyingPrice = null;
|
|
baseInfo.NoRiskRate = null;
|
|
baseInfo.DividendRate = null;
|
|
baseInfo.Vol = null;
|
|
baseInfo.ExtendInfo = null;
|
|
|
|
postData["BaseInfo"] = baseInfo;
|
|
|
|
postData["ExtendInfo"] = extendInfo;
|
|
//计算场景
|
|
postData["CalcScenario"] = calcScenario.ToString();
|
|
var log = LogFactory.GetLogger<HttpClientWrap>();
|
|
var jsonStr = JsonHelper.Serialize(postData);
|
|
log.Info("调用外部接口计算自定义交易请求" + jsonStr);
|
|
var res = PostJson("api/v1/structure/calculate", postData);
|
|
ReturnInfo<TradeValueResult> result;
|
|
try
|
|
{
|
|
LogFactory.GetLogger<HttpClientWrap>().Info(res);
|
|
var obj = JsonHelper.Deserialize<TempValueResult>(res);
|
|
if (obj == null)
|
|
{
|
|
return Return.Fail<TradeValueResult>("返回信息无法解析:" + res);
|
|
}
|
|
if (obj.errcode == 0)
|
|
{
|
|
result = Return.Success<TradeValueResult>(obj, obj.errmsg);
|
|
|
|
result.Content.Pv = result.Content.Pv * t.Notional;
|
|
result.Content.Delta = result.Content.Delta * t.Notional;
|
|
result.Content.Gamma = result.Content.Gamma * t.Notional;
|
|
result.Content.Vega = result.Content.Vega * t.Notional;
|
|
result.Content.CalendarDayTheta = result.Content.CalendarDayTheta * t.Notional;
|
|
result.Content.TradingDayTheta = result.Content.TradingDayTheta * t.Notional;
|
|
result.Content.Rho = result.Content.Rho * t.Notional;
|
|
|
|
if (t.BuySell == "卖出")
|
|
{
|
|
result.Content.Pv = -result.Content.Pv;
|
|
result.Content.Delta = -result.Content.Delta;
|
|
result.Content.Gamma = -result.Content.Gamma;
|
|
result.Content.Vega = -result.Content.Vega;
|
|
result.Content.CalendarDayTheta = -result.Content.CalendarDayTheta;
|
|
result.Content.TradingDayTheta = -result.Content.TradingDayTheta;
|
|
result.Content.Rho = -result.Content.Rho;
|
|
}
|
|
|
|
result.Content.DeltaCash = result.Content.Delta * spotPrice;
|
|
result.Content.GammaCash = result.Content.Gamma * Math.Pow(spotPrice, 2) / 100;
|
|
result.Content.VegaCash = result.Content.Vega * spotPrice;
|
|
//广期计算的Rho是100bp的结果,这里需要改为1bp;
|
|
result.Content.Rho = result.Content.Rho / 100;
|
|
|
|
}
|
|
else
|
|
{
|
|
result = Return.Fail<TradeValueResult>(obj.errmsg, obj);
|
|
}
|
|
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
result = Return.Fail<TradeValueResult>("调用外部接口失败:" + ex.Message);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
|
|
internal class TempValueResult
|
|
{
|
|
public int errcode { get; set; }
|
|
public string errmsg { get; set; }
|
|
public string CalcId { get; set; }
|
|
public double Pv { get; set; }
|
|
public double Vega { get; set; }
|
|
public double Delta { get; set; }
|
|
public double Gamma { get; set; }
|
|
public double Rho { get; set; }
|
|
public double Theta { get; set; }
|
|
public double Margin { get; set; }
|
|
public double Volatility { get; set; }
|
|
|
|
public static implicit operator TradeValueResult(TempValueResult obj)
|
|
{
|
|
return new TradeValueResult()
|
|
{
|
|
Pv = obj.Pv,
|
|
Delta = obj.Delta,
|
|
Gamma = obj.Gamma,
|
|
Vega = obj.Vega,
|
|
Rho = obj.Rho,
|
|
CalendarDayTheta = obj.Theta,
|
|
TradingDayTheta = obj.Theta,
|
|
Margin = obj.Margin,
|
|
Vol = obj.Volatility,
|
|
};
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|