klhztrader/KLHZ.Trader.Core.Math/Declisions/Utils/TwoPeriods.cs

366 lines
15 KiB
C#

using KLHZ.Trader.Core.Contracts.Declisions.Dtos;
using KLHZ.Trader.Core.Contracts.Declisions.Dtos.Enums;
using KLHZ.Trader.Core.Contracts.Declisions.Interfaces;
using KLHZ.Trader.Core.Math.Declisions.Dtos;
using KLHZ.Trader.Core.Math.Declisions.Services.Cache;
namespace KLHZ.Trader.Core.Math.Declisions.Utils
{
/// <summary>
/// Обработка последних интервалов истории изменения цен.
/// </summary>
public static class TwoPeriods
{
internal static PeriodPricesInfoDto GetPriceDiffForTimeSpan(this IPriceHistoryCacheUnit unit, TimeSpan timeShift, TimeSpan timeSpan, int? pointsShift = null)
{
var res = new PeriodPricesInfoDto(false, 0, 0, 0, 0, 0, timeSpan, 0, 0);
var data = unit.GetData().Result;
var times = data.timestamps;
var prices = data.prices;
if (times.Length < 2) return res;
var lastPriceTime = times[times.Length - 1];
var intervalEnd = lastPriceTime - timeShift;
var intervalStart = intervalEnd - timeSpan;
var max = decimal.MinValue;
var min = decimal.MaxValue;
var intervaEndIndex = -1;
var intervaStartIndex = -1;
int count = 0;
for (int i = times.Length - 1; i > -1; i--)
{
if ((times[i] <= intervalEnd || pointsShift.HasValue && count < pointsShift.Value) && intervaEndIndex < 0)
{
intervaEndIndex = i;
}
if (prices[i] > max && intervaEndIndex >= 0)
{
max = prices[i];
}
if (prices[i] < min && intervaEndIndex >= 0)
{
min = prices[i];
}
if (times[i] <= intervalStart && intervaStartIndex < 0)
{
intervaStartIndex = i;
if (intervaStartIndex != intervaEndIndex && intervaEndIndex >= 0)
break;
}
count++;
}
if (intervaStartIndex >= 0 && intervaEndIndex >= 0)
{
res = new PeriodPricesInfoDto(
true,
prices[intervaStartIndex],
prices[intervaEndIndex],
prices[intervaEndIndex] - prices[intervaStartIndex],
min,
max,
timeSpan,
intervaStartIndex,
intervaEndIndex);
}
return res;
}
internal static bool CheckStable(this PeriodPricesInfoDto data, decimal meanfullDiff)
{
meanfullDiff = System.Math.Abs(meanfullDiff);
return data.Success && System.Math.Abs(data.PeriodDiff) < 1.5m * meanfullDiff && System.Math.Abs(data.PeriodMax - data.PeriodMin) < 2 * meanfullDiff;
}
internal static bool CheckGrowing(this PeriodPricesInfoDto data, decimal meanfullDiff)
{
return meanfullDiff > 0 && data.Success && data.PeriodDiff > meanfullDiff && System.Math.Abs(data.PeriodMax - data.PeriodMin) < 3 * System.Math.Abs(data.PeriodDiff);
}
internal static bool CheckFalling(this PeriodPricesInfoDto data, decimal meanfullDiff)
{
meanfullDiff = -meanfullDiff;
return meanfullDiff < 0 && data.Success && data.PeriodDiff < meanfullDiff && System.Math.Abs(data.PeriodMax - data.PeriodMin) < 3 * System.Math.Abs(data.PeriodDiff);
}
internal static float CalcTrendRelationAbs(PeriodPricesInfoDto first, PeriodPricesInfoDto second)
{
var k1 = System.Math.Abs(first.PeriodDiff) / System.Math.Abs((decimal)first.Period.TotalSeconds);
var k2 = System.Math.Abs(second.PeriodDiff) / System.Math.Abs((decimal)second.Period.TotalSeconds);
if (k2 == 0 && k1 != 0) return 1000;
return (float)(k1 / k2);
}
internal static float CalcTrendRelationAbs(TwoPeriodsResultDto data)
{
var k1 = System.Math.Abs(data.DiffStart) / System.Math.Abs((decimal)data.PeriodStart.TotalSeconds);
var k2 = System.Math.Abs(data.DiffEnd) / System.Math.Abs((decimal)data.PeriodEnd.TotalSeconds);
if (k2 == 0 && k1 != 0) return 1000;
return (float)(k1 / k2);
}
internal static bool CheckDowntrendEnding(this IPriceHistoryCacheUnit unit, TimeSpan firstPeriod, TimeSpan secondPeriod, decimal meanfullDiff)
{
var totalDiff = unit.GetPriceDiffForTimeSpan(TimeSpan.Zero, firstPeriod + secondPeriod);
var startDiff = unit.GetPriceDiffForTimeSpan(secondPeriod, firstPeriod);
var endDiff = unit.GetPriceDiffForTimeSpan(TimeSpan.Zero, secondPeriod);
var isEndStable = endDiff.CheckStable(meanfullDiff);
var isEndGrown = endDiff.CheckGrowing(meanfullDiff);
var isStartFalls = startDiff.CheckFalling(meanfullDiff);
var isTotalFalls = totalDiff.CheckFalling(meanfullDiff);
var trendRelation = CalcTrendRelationAbs(startDiff, endDiff);
var res = totalDiff.Success && isStartFalls && (isEndStable || isEndGrown) && trendRelation >= 2;
if (startDiff.Success)
{
}
return res;
}
internal static bool CheckUptrendEnding(this IPriceHistoryCacheUnit unit, TimeSpan firstPeriod, TimeSpan secondPeriod, decimal meanfullDiff)
{
var totalDiff = unit.GetPriceDiffForTimeSpan(TimeSpan.Zero, firstPeriod + secondPeriod);
var startDiff = unit.GetPriceDiffForTimeSpan(secondPeriod, firstPeriod);
var endDiff = unit.GetPriceDiffForTimeSpan(TimeSpan.Zero, secondPeriod);
var isEndStable = endDiff.CheckStable(meanfullDiff);
var isEndFalls = endDiff.CheckFalling(meanfullDiff);
var isStartGrows = startDiff.CheckGrowing(meanfullDiff);
var trendRelation = CalcTrendRelationAbs(startDiff, endDiff);
var isEndLocal = endDiff.PeriodDiff == 0;
var res = totalDiff.Success && isStartGrows && (isEndStable || isEndFalls) && trendRelation >= 2 && !isEndLocal;
if (res)
{
}
return res;
}
internal static bool CheckDowntrendStarting(this PriceHistoryCacheUnit unit, TimeSpan firstPeriod, TimeSpan secondPeriod, decimal meanfullDiff)
{
var totalDiff = unit.GetPriceDiffForTimeSpan(TimeSpan.Zero, firstPeriod + secondPeriod);
var startDiff = unit.GetPriceDiffForTimeSpan(secondPeriod, firstPeriod);
var endDiff = unit.GetPriceDiffForTimeSpan(TimeSpan.Zero, secondPeriod);
var isEndFalls = endDiff.CheckFalling(meanfullDiff);
var isStartStable = startDiff.CheckStable(meanfullDiff);
var isStartGrows = startDiff.CheckGrowing(meanfullDiff);
var trendRelation = CalcTrendRelationAbs(endDiff, startDiff);
return totalDiff.Success && (isStartStable || isStartGrows) && isEndFalls && trendRelation >= 2;
}
internal static bool CheckUptrendStarting(this PriceHistoryCacheUnit unit, TimeSpan firstPeriod, TimeSpan secondPeriod, decimal meanfullDiff)
{
var totalDiff = unit.GetPriceDiffForTimeSpan(TimeSpan.Zero, firstPeriod + secondPeriod);
var startDiff = unit.GetPriceDiffForTimeSpan(secondPeriod, firstPeriod);
var endDiff = unit.GetPriceDiffForTimeSpan(TimeSpan.Zero, secondPeriod);
var isEndGrows = endDiff.CheckGrowing(meanfullDiff);
var isStartStable = startDiff.CheckStable(meanfullDiff);
var isStartFalls = startDiff.CheckStable(meanfullDiff);
var trendRelation = CalcTrendRelationAbs(endDiff, startDiff);
var res = totalDiff.Success && (isStartStable || isStartFalls) && isEndGrows && endDiff.PeriodDiff > meanfullDiff;
if (isStartStable)
{
res &= trendRelation >= 2;
}
else
{
}
if (res)
{
}
return res;
}
internal static TwoPeriodsResultDto GetTwoPeriodsProcessingData(this (DateTime[] timestamps, decimal[] prices) data, TimeSpan shift, int shiftPointsStart, int shiftPointsEnd, TimeSpan firstPeriod, decimal meanfullDiff)
{
var res = new TwoPeriodsResultDto(success: false, 0, 0, 0, 0, 0, TimeSpan.Zero, TimeSpan.Zero);
var time = data.timestamps;
var prices = data.prices;
int count = -1;
var lastTime = time[time.Length - 1];
var bound = -1;
var start = -1;
var end = time.Length - 1;
for (int i = time.Length - 1; i > -1; i--)
{
if (count > 0 && bound < 0 && (count == shiftPointsEnd || lastTime - time[i] >= shift))
{
bound = i;
shift = lastTime - time[i];
}
if (lastTime - time[i] >= shift + firstPeriod)
{
start = i;
break;
}
count++;
}
if (start < bound && start >= 0 && bound > 0)
{
var diff1 = prices[bound] - prices[start];
var diff2 = prices[end] - prices[bound];
res = new TwoPeriodsResultDto(true, diff1, diff2, start, bound, end, time[bound] - time[start], time[end] - time[bound]);
}
return res;
}
public static bool CheckLongClose(this IPriceHistoryCacheUnit unit, TimeSpan firstPeriod, TimeSpan secondPeriod, decimal meanfullDiff, int pointsStart, int pointsEnd)
{
var data = unit.GetData().Result;
var periodStat = data.GetTwoPeriodsProcessingData(secondPeriod, pointsStart, pointsEnd, firstPeriod, meanfullDiff);
var trendRelation = CalcTrendRelationAbs(periodStat);
var isStartOk = periodStat.Success && periodStat.DiffStart > 0 && periodStat.DiffStart > 1.5m * meanfullDiff;
var isEndOk = periodStat.Success && periodStat.DiffEnd < meanfullDiff;
if (isEndOk)
{
}
if (isStartOk)
{
}
if (isEndOk && isStartOk)
{
}
return isStartOk && isEndOk && data.prices[periodStat.End] - data.prices[periodStat.Start] >= meanfullDiff;
}
internal static bool CheckUptrendStarting2(this IPriceHistoryCacheUnit unit, TimeSpan firstPeriod, TimeSpan secondPeriod, decimal meanfullDiff)
{
var data = unit.GetData().Result;
var periodStat = data.GetTwoPeriodsProcessingData(secondPeriod, 15, 2, firstPeriod, meanfullDiff);
var trendRelation = CalcTrendRelationAbs(periodStat);
var isStartOk = periodStat.Success && periodStat.DiffStart < -meanfullDiff;
var isEndOk = periodStat.Success && periodStat.DiffEnd >= meanfullDiff;
if (isEndOk)
{
}
if (isStartOk)
{
}
if (isEndOk && isStartOk)
{
}
return isStartOk && isEndOk;
}
internal static bool _CheckUptrendStarting2(this IPriceHistoryCacheUnit unit, TimeSpan firstPeriod, TimeSpan secondPeriod, decimal meanfullDiff)
{
var data = unit.GetData().Result;
var periodStat = data.GetTwoPeriodsProcessingData(secondPeriod, 15, 1, firstPeriod, meanfullDiff);
var trendRelation = CalcTrendRelationAbs(periodStat);
var isStartOk = periodStat.Success && periodStat.DiffStart < -meanfullDiff;
var isEndOk = periodStat.Success && periodStat.DiffEnd >= meanfullDiff;
if (isEndOk)
{
}
if (isStartOk)
{
}
if (isEndOk && isStartOk)
{
}
return isStartOk && isEndOk;
}
public static bool CheckLongOpen(this IPriceHistoryCacheUnit unit, TimeSpan firstPeriod, TimeSpan secondPeriod, decimal meanfullDiff, int pointsStart, int pointsEnd)
{
var data = unit.GetData().Result;
var periodStat = data.GetTwoPeriodsProcessingData(secondPeriod, pointsStart, pointsEnd, firstPeriod, meanfullDiff);
var trendRelation = CalcTrendRelationAbs(periodStat);
var isStartOk = periodStat.Success && periodStat.DiffStart < -meanfullDiff;
var isEndOk = periodStat.Success && periodStat.DiffEnd >= meanfullDiff;
if (isEndOk)
{
}
if (isStartOk)
{
}
if (isEndOk && isStartOk)
{
}
return isStartOk && isEndOk && data.prices[periodStat.Start] - data.prices[periodStat.End] >= meanfullDiff;
}
public static TradingEvent Detect(IPriceHistoryCacheUnit data)
{
decimal meanfullDiff;
if (data.Figi == "BBG004730N88")
{
meanfullDiff = 0.05m;
}
else if (data.Figi == "FUTIMOEXF000")
{
meanfullDiff = 1m;
}
else
{
return TradingEvent.None;
}
var res = TradingEvent.None;
//var downtrendStarts = data.CheckDowntrendStarting(TimeSpan.FromSeconds(30), TimeSpan.FromSeconds(7), meanfullDiff);
var uptrendStarts = data.CheckLongOpen(TimeSpan.FromSeconds(60), TimeSpan.FromSeconds(7), meanfullDiff, 8, 3);
var uptrendStarts2 = data.CheckLongOpen(TimeSpan.FromSeconds(60), TimeSpan.FromSeconds(3), meanfullDiff, 15, 2);
var downtrendEnds = data.CheckLongOpen(TimeSpan.FromSeconds(120), TimeSpan.FromSeconds(10), meanfullDiff, 15, 5);
uptrendStarts |= downtrendEnds;
uptrendStarts |= uptrendStarts2;
if (uptrendStarts)
{
res |= TradingEvent.LongClose;
}
//var downtrendEnds = data.CheckDowntrendEnding(TimeSpan.FromSeconds(60), TimeSpan.FromSeconds(15), meanfullDiff);
var uptrendEnds = data.CheckLongClose(TimeSpan.FromSeconds(15), TimeSpan.FromSeconds(20), meanfullDiff * 1.5m, 8, 8);
var uptrendEnds2 = data.CheckLongClose(TimeSpan.FromSeconds(120), TimeSpan.FromSeconds(30), meanfullDiff, 15, 8);
uptrendEnds |= uptrendEnds2;
if (uptrendEnds)
{
res |= TradingEvent.LongOpen;
}
return res;
}
}
}