96 lines
4.2 KiB
C#
96 lines
4.2 KiB
C#
using NPOI.SS.Formula.Functions;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using System.Text.RegularExpressions;
|
|
using System.Threading.Tasks;
|
|
using YLErp.Abstract.DataProviders;
|
|
using YLErp.Models;
|
|
using YLErp.Modules.DataProviderModule;
|
|
|
|
namespace YLErp.BLL.MarginCalculation.DongWu
|
|
{
|
|
public class UpDownLimitMargin3Provider : IUpDownLimitProvider
|
|
{
|
|
private DateTime settleDate;
|
|
private string underlyingCode;
|
|
readonly IUnderlyingDataProvider underlyingDataProvider;
|
|
public UpDownLimitMargin3Provider(DateTime settleDate, string underlyingCode)
|
|
{
|
|
this.settleDate = settleDate;
|
|
this.underlyingCode = underlyingCode;
|
|
this.underlyingDataProvider = new UnderlyingDataProvider();
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// 获取连续两日最大涨跌幅的95分位和5分位
|
|
/// ---------------------------------------------------------------------
|
|
/// 例如,对于CF209合约,选取CFFI.WI过去600天内的价格序列,对于任意日T,
|
|
/// 其两日最大涨幅=Max(T+1最高价,T+2最高价)/T日收盘价
|
|
/// 两日最大跌幅 = Min(T + 1最低价,T + 2最低价) / T日收盘价
|
|
/// 得到最大涨跌幅的序列后,取95分位和5分位的百分比作为连续两日最大涨跌幅的95分位数值。
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
public InnerUpDownLimit GetUpDownLimit()
|
|
{
|
|
var startDate = settleDate.AddDays(-600);
|
|
var mainUnderlyingCode = underlyingCode;
|
|
|
|
var um = underlyingDataProvider.GetUnderlying(underlyingCode);
|
|
if (um.IsFutures())
|
|
{
|
|
// 如果是期货类型的,需要获取到主合约
|
|
// 忽略大小写,将字母后的数字替换为00,获取到主合约Code
|
|
Regex myRegex = new Regex(@"^([a-zA-Z]*)(\d*)$", RegexOptions.IgnoreCase);
|
|
mainUnderlyingCode = myRegex.Replace(underlyingCode, "$1") + "00";
|
|
}
|
|
var eodPrices = EodPriceQueryService.GetEodPriceByUnserialDateRange(startDate, settleDate, mainUnderlyingCode).OrderBy(b => b.ValueDate).ToList();
|
|
|
|
|
|
int lastIndex = eodPrices.Count - 1;
|
|
List<InnerUpDownLimit> innerCodes = new List<InnerUpDownLimit>();
|
|
for (int i = 0; i < eodPrices.Count; i++)
|
|
{
|
|
if (i == lastIndex - 1)
|
|
{
|
|
// 最后两天没有T+1和T+2,不放到列表中统计95分位和5分位;
|
|
break;
|
|
}
|
|
EodPrice t0 = eodPrices[i];
|
|
EodPrice t1 = (i + 1) > lastIndex ? null : eodPrices[i + 1];
|
|
EodPrice t2 = (i + 2) > lastIndex ? null : eodPrices[i + 2];
|
|
var uplimitRate = Math.Max(t1?.HighPrice ?? 0, t2?.HighPrice ?? 0) / t0.ClosePrice;
|
|
var downLimitRate = Math.Min(t1?.LowPrice ?? 0, t2?.LowPrice ?? 0) / t0.ClosePrice;
|
|
InnerUpDownLimit innerCode = new InnerUpDownLimit()
|
|
{
|
|
UnderlyingCode = t0.UnderlyingCode,
|
|
//ClosePrice = t0.ClosePrice,
|
|
UplimitRate = uplimitRate,
|
|
DownLimitRate = downLimitRate
|
|
};
|
|
innerCodes.Add(innerCode);
|
|
}
|
|
|
|
//最大涨幅95分位和5分位
|
|
List<double> priceList = new List<double>();
|
|
priceList.AddRange(innerCodes.Select(g => g.UplimitRate));
|
|
priceList.AddRange(innerCodes.Select(g => g.DownLimitRate));
|
|
|
|
var OrderPriceList = priceList.OrderBy(g => g);
|
|
var totalCount = OrderPriceList.Count();
|
|
var uplimitRatePercent95 = totalCount == 0 ? 0 : Math.Abs(1-OrderPriceList.ElementAt((int)(totalCount * 0.95)));
|
|
var downLimitRatePercent5 = totalCount == 0 ? 0 : Math.Abs(1-OrderPriceList.ElementAt((int)(totalCount * 0.05)));
|
|
|
|
|
|
return new InnerUpDownLimit()
|
|
{
|
|
UnderlyingCode = underlyingCode,
|
|
UplimitRate = totalCount == 0 ? 0 : uplimitRatePercent95,
|
|
DownLimitRate = totalCount == 0 ? 0 : downLimitRatePercent5
|
|
};
|
|
}
|
|
}
|
|
}
|