Files
zszq-trs/YLErpDAL/Modules/ApiModule/TradeCalcApiHelper.cs
2024-05-09 14:06:26 +08:00

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,
};
}
}
}
}