320 lines
13 KiB
C#
320 lines
13 KiB
C#
using KLHZ.Trader.Core.Declisions.Models;
|
|
|
|
namespace KLHZ.Trader.Core.Declisions.Utils
|
|
{
|
|
internal static class HistoryProcessingInstruments
|
|
{
|
|
internal static PeriodPricesInfo GetPriceDiffForTimeSpan(this PriceHistoryCacheUnit unit, TimeSpan timeShift, TimeSpan timeSpan, int? pointsShift = null)
|
|
{
|
|
var res = new PeriodPricesInfo(false, 0, 0, 0, 0, 0, timeSpan, 0, 0);
|
|
var data = unit.GetData();
|
|
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 = float.MinValue;
|
|
var min = float.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 PeriodPricesInfo(
|
|
true,
|
|
prices[intervaStartIndex],
|
|
prices[intervaEndIndex],
|
|
prices[intervaEndIndex] - prices[intervaStartIndex],
|
|
min,
|
|
max,
|
|
timeSpan,
|
|
intervaStartIndex,
|
|
intervaEndIndex);
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
internal static bool CheckStable(this PeriodPricesInfo data, float meanfullDiff)
|
|
{
|
|
meanfullDiff = Math.Abs(meanfullDiff);
|
|
return data.Success && Math.Abs(data.PeriodDiff) < 1.5 * meanfullDiff && Math.Abs(data.PeriodMax - data.PeriodMin) < 2 * meanfullDiff;
|
|
}
|
|
|
|
internal static bool CheckGrowing(this PeriodPricesInfo data, float meanfullDiff)
|
|
{
|
|
return meanfullDiff > 0 && data.Success && data.PeriodDiff > meanfullDiff && Math.Abs(data.PeriodMax - data.PeriodMin) < 3 * Math.Abs(data.PeriodDiff);
|
|
}
|
|
|
|
internal static bool CheckFalling(this PeriodPricesInfo data, float meanfullDiff)
|
|
{
|
|
meanfullDiff = -meanfullDiff;
|
|
return meanfullDiff < 0 && data.Success && data.PeriodDiff < meanfullDiff && Math.Abs(data.PeriodMax - data.PeriodMin) < 3 * Math.Abs(data.PeriodDiff);
|
|
}
|
|
|
|
internal static float CalcTrendRelationAbs(PeriodPricesInfo first, PeriodPricesInfo second)
|
|
{
|
|
var k1 = Math.Abs(first.PeriodDiff) / Math.Abs(first.Period.TotalSeconds);
|
|
var k2 = Math.Abs(second.PeriodDiff) / Math.Abs(second.Period.TotalSeconds);
|
|
if (k2 == 0 && k1 != 0) return 1000;
|
|
return (float)(k1 / k2);
|
|
}
|
|
internal static float CalcTrendRelationAbs(TwoPeriodsProcessingData data)
|
|
{
|
|
var k1 = Math.Abs(data.DiffStart) / Math.Abs(data.PeriodStart.TotalSeconds);
|
|
var k2 = Math.Abs(data.DiffEnd) / Math.Abs(data.PeriodEnd.TotalSeconds);
|
|
if (k2 == 0 && k1 != 0) return 1000;
|
|
return (float)(k1 / k2);
|
|
}
|
|
|
|
internal static bool CheckDowntrendEnding(this PriceHistoryCacheUnit unit, TimeSpan firstPeriod, TimeSpan secondPeriod, float 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 PriceHistoryCacheUnit unit, TimeSpan firstPeriod, TimeSpan secondPeriod, float 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, float 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, float 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 TwoPeriodsProcessingData GetTwoPeriodsProcessingData(this (DateTime[] timestamps, float[] prices) data, TimeSpan shift, int shiftPointsStart, int shiftPointsEnd, TimeSpan firstPeriod, float meanfullDiff)
|
|
{
|
|
var res = new TwoPeriodsProcessingData(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 TwoPeriodsProcessingData(true, diff1, diff2, start, bound, end, time[bound] - time[start], time[end] - time[bound]);
|
|
}
|
|
return res;
|
|
}
|
|
|
|
internal static bool CheckLongClose(this PriceHistoryCacheUnit unit, TimeSpan firstPeriod, TimeSpan secondPeriod, float meanfullDiff, int pointsStart, int pointsEnd)
|
|
{
|
|
var data = unit.GetData();
|
|
var periodStat = data.GetTwoPeriodsProcessingData(secondPeriod, pointsStart, pointsEnd, firstPeriod, meanfullDiff);
|
|
var trendRelation = CalcTrendRelationAbs(periodStat);
|
|
var isStartOk = periodStat.Success && periodStat.DiffStart > 0 && periodStat.DiffStart > 1.5 * 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 PriceHistoryCacheUnit unit, TimeSpan firstPeriod, TimeSpan secondPeriod, float meanfullDiff)
|
|
{
|
|
var data = unit.GetData();
|
|
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 PriceHistoryCacheUnit unit, TimeSpan firstPeriod, TimeSpan secondPeriod, float meanfullDiff)
|
|
{
|
|
var data = unit.GetData();
|
|
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;
|
|
}
|
|
|
|
|
|
internal static bool CheckLongOpen(this PriceHistoryCacheUnit unit, TimeSpan firstPeriod, TimeSpan secondPeriod, float meanfullDiff, int pointsStart, int pointsEnd)
|
|
{
|
|
var data = unit.GetData();
|
|
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);
|
|
}
|
|
}
|
|
}
|