Compare commits

...

4 Commits

Author SHA1 Message Date
vlad zverzhkhovskiy 6884407f12 добавил анализ скользящими средними
test / deploy_trader_prod (push) Successful in 19m5s Details
2025-09-02 23:51:10 +03:00
vlad zverzhkhovskiy d0786cfe19 корректная обработка истории. 2025-09-02 22:21:49 +03:00
vlad zverzhkhovskiy fbd3da2b8d перешел с float на decimal в расчётаз 2025-09-02 21:54:35 +03:00
vlad zverzhkhovskiy ff1090c819 фиксация перед заменой float на decimal 2025-09-02 17:46:30 +03:00
14 changed files with 260 additions and 215 deletions

View File

@ -5,13 +5,13 @@
public readonly int Start; public readonly int Start;
public readonly int Bound; public readonly int Bound;
public readonly int End; public readonly int End;
public readonly float DiffStart; public readonly decimal DiffStart;
public readonly float DiffEnd; public readonly decimal DiffEnd;
public readonly bool Success; public readonly bool Success;
public readonly TimeSpan PeriodStart; public readonly TimeSpan PeriodStart;
public readonly TimeSpan PeriodEnd; public readonly TimeSpan PeriodEnd;
public TwoPeriodsResultDto(bool success, float diffStart, float diffEnd, int start, int bound, int end, public TwoPeriodsResultDto(bool success, decimal diffStart, decimal diffEnd, int start, int bound, int end,
TimeSpan periodStart, TimeSpan periodEnd) TimeSpan periodStart, TimeSpan periodEnd)
{ {
Success = success; Success = success;

View File

@ -7,9 +7,17 @@ namespace KLHZ.Trader.Core.Contracts.Declisions.Interfaces
public string Figi { get; } public string Figi { get; }
public int Length { get; } public int Length { get; }
public ValueTask AddData(INewPrice priceChange); public ValueTask AddData(INewPrice priceChange);
public ValueTask<(DateTime[] timestamps, float[] prices)> GetData(); public ValueTask<(DateTime[] timestamps, decimal[] prices)> GetData();
public ValueTask AddOrderbook(IOrderbook orderbook); public ValueTask AddOrderbook(IOrderbook orderbook);
/// <summary>
/// Число заявок на продаже в стакане.
/// </summary>
public decimal AsksCount { get; } public decimal AsksCount { get; }
/// <summary>
/// Число заявок на покупку в стакане.
/// </summary>
public decimal BidsCount { get; } public decimal BidsCount { get; }
} }
} }

View File

@ -2,7 +2,7 @@
{ {
public static class Lines public static class Lines
{ {
public static (float x, float y) LinesCrossing(float k1, float b1, float k2, float b2) public static (decimal x, decimal y) LinesCrossing(decimal k1, decimal b1, decimal k2, decimal b2)
{ {
var x = (b2 - b1) / (k1 - k2); var x = (b2 - b1) / (k1 - k2);
var y = k1 * x + b1; var y = k1 * x + b1;
@ -10,10 +10,10 @@
return (x, y); return (x, y);
} }
public static bool IsLinesCrossing(DateTime time1, DateTime time2, float val1_1, float val1_2, float val2_1, float val2_2) public static bool IsLinesCrossing(DateTime time1, DateTime time2, decimal val1_1, decimal val1_2, decimal val2_1, decimal val2_2)
{ {
var dtime = (float)(time2 - time1).TotalSeconds; var dtime = (decimal)(time2 - time1).TotalSeconds;
if (dtime == 0) return false;
var dval1 = val1_2 - val1_1; var dval1 = val1_2 - val1_1;
var k1 = dval1 / dtime; var k1 = dval1 / dtime;
var b1 = val1_1; var b1 = val1_1;
@ -25,8 +25,11 @@
if (k1 != k2) if (k1 != k2)
{ {
var cross = LinesCrossing(k1, b1, k2, b2); var cross = LinesCrossing(k1, b1, k2, b2);
var crossingTimestamp = time1.AddSeconds(cross.x); if (cross.x>=0 && cross.x <= dtime)
return crossingTimestamp >= time1 && crossingTimestamp <= time2; {
var crossingTimestamp = time1.AddSeconds((double)cross.x);
return crossingTimestamp >= time1 && crossingTimestamp <= time2;
}
} }
return false; return false;
} }

View File

@ -4,15 +4,15 @@
{ {
public readonly int Start; public readonly int Start;
public readonly int End; public readonly int End;
public readonly float LastPrice; public readonly decimal LastPrice;
public readonly float FirstPrice; public readonly decimal FirstPrice;
public readonly float PeriodDiff; public readonly decimal PeriodDiff;
public readonly float PeriodMax; public readonly decimal PeriodMax;
public readonly float PeriodMin; public readonly decimal PeriodMin;
public readonly bool Success; public readonly bool Success;
public readonly TimeSpan Period; public readonly TimeSpan Period;
public PeriodPricesInfoDto(bool success, float firstPrice, float lastPrice, float periodDiff, float periodMin, float periodMax, TimeSpan period, int start, int end) public PeriodPricesInfoDto(bool success, decimal firstPrice, decimal lastPrice, decimal periodDiff, decimal periodMin, decimal periodMax, TimeSpan period, int start, int end)
{ {
Success = success; Success = success;
LastPrice = lastPrice; LastPrice = lastPrice;

View File

@ -24,7 +24,7 @@ namespace KLHZ.Trader.Core.Math.Declisions.Services.Cache
public decimal BidsCount => 1; public decimal BidsCount => 1;
private readonly object _locker = new(); private readonly object _locker = new();
private readonly float[] Prices = new float[CacheMaxLength]; private readonly decimal[] Prices = new decimal[CacheMaxLength];
private readonly DateTime[] Timestamps = new DateTime[CacheMaxLength]; private readonly DateTime[] Timestamps = new DateTime[CacheMaxLength];
private int _length = 0; private int _length = 0;
@ -36,7 +36,7 @@ namespace KLHZ.Trader.Core.Math.Declisions.Services.Cache
Array.Copy(Prices, 1, Prices, 0, Prices.Length - 1); Array.Copy(Prices, 1, Prices, 0, Prices.Length - 1);
Array.Copy(Timestamps, 1, Timestamps, 0, Timestamps.Length - 1); Array.Copy(Timestamps, 1, Timestamps, 0, Timestamps.Length - 1);
Prices[Prices.Length - 1] = (float)priceChange.Value; Prices[Prices.Length - 1] = priceChange.Value;
Timestamps[Timestamps.Length - 1] = priceChange.Time; Timestamps[Timestamps.Length - 1] = priceChange.Time;
if (_length < CacheMaxLength) if (_length < CacheMaxLength)
@ -47,11 +47,11 @@ namespace KLHZ.Trader.Core.Math.Declisions.Services.Cache
return ValueTask.CompletedTask; return ValueTask.CompletedTask;
} }
public ValueTask<(DateTime[] timestamps, float[] prices)> GetData() public ValueTask<(DateTime[] timestamps, decimal[] prices)> GetData()
{ {
lock (_locker) lock (_locker)
{ {
var prices = new float[_length]; var prices = new decimal[_length];
var timestamps = new DateTime[_length]; var timestamps = new DateTime[_length];
Array.Copy(Prices, Prices.Length - _length, prices, 0, prices.Length); Array.Copy(Prices, Prices.Length - _length, prices, 0, prices.Length);
Array.Copy(Timestamps, Prices.Length - _length, timestamps, 0, timestamps.Length); Array.Copy(Timestamps, Prices.Length - _length, timestamps, 0, timestamps.Length);
@ -79,7 +79,7 @@ namespace KLHZ.Trader.Core.Math.Declisions.Services.Cache
.Skip(priceChanges.Length - CacheMaxLength) .Skip(priceChanges.Length - CacheMaxLength)
.ToArray(); .ToArray();
var prices = selectedPriceChanges var prices = selectedPriceChanges
.Select(pc => (float)pc.Value) .Select(pc => pc.Value)
.ToArray(); .ToArray();
var times = selectedPriceChanges var times = selectedPriceChanges
.Select(pc => pc.Time) .Select(pc => pc.Time)

View File

@ -44,7 +44,7 @@ namespace KLHZ.Trader.Core.Math.Declisions.Services.Cache
} }
private readonly object _locker = new(); private readonly object _locker = new();
private readonly float[] Prices = new float[_arrayMaxLength]; private readonly decimal[] Prices = new decimal[_arrayMaxLength];
private readonly DateTime[] Timestamps = new DateTime[_arrayMaxLength]; private readonly DateTime[] Timestamps = new DateTime[_arrayMaxLength];
private int _length = 0; private int _length = 0;
@ -59,7 +59,7 @@ namespace KLHZ.Trader.Core.Math.Declisions.Services.Cache
lock (_locker) lock (_locker)
{ {
_pointer++; _pointer++;
Prices[_pointer] = (float)priceChange.Value; Prices[_pointer] = priceChange.Value;
Timestamps[_pointer] = priceChange.Time; Timestamps[_pointer] = priceChange.Time;
if (_length < CacheMaxLength) if (_length < CacheMaxLength)
{ {
@ -76,17 +76,17 @@ namespace KLHZ.Trader.Core.Math.Declisions.Services.Cache
return ValueTask.CompletedTask; return ValueTask.CompletedTask;
} }
public ValueTask<(DateTime[] timestamps, float[] prices)> GetData() public ValueTask<(DateTime[] timestamps, decimal[] prices)> GetData()
{ {
lock (_locker) lock (_locker)
{ {
if (_pointer < 0) if (_pointer < 0)
{ {
return ValueTask.FromResult((Array.Empty<DateTime>(), Array.Empty<float>())); return ValueTask.FromResult((Array.Empty<DateTime>(), Array.Empty<decimal>()));
} }
else else
{ {
var prices = new float[_length]; var prices = new decimal[_length];
var timestamps = new DateTime[_length]; var timestamps = new DateTime[_length];
Array.Copy(Prices, 1 + _pointer - _length, prices, 0, prices.Length); Array.Copy(Prices, 1 + _pointer - _length, prices, 0, prices.Length);
Array.Copy(Timestamps, 1 + _pointer - _length, timestamps, 0, timestamps.Length); Array.Copy(Timestamps, 1 + _pointer - _length, timestamps, 0, timestamps.Length);
@ -123,7 +123,7 @@ namespace KLHZ.Trader.Core.Math.Declisions.Services.Cache
foreach (var pc in selectedPriceChanges) foreach (var pc in selectedPriceChanges)
{ {
AddData(pc); AddData(pc).AsTask().Wait();
} }
} }
} }

View File

@ -5,10 +5,10 @@ namespace KLHZ.Trader.Core.Math.Declisions.Utils
{ {
public static class MovingAverage public static class MovingAverage
{ {
private static (DateTime time, float value) CalcTimeWindowAverageValue(DateTime[] timestamps, float[] values, int window, int shift = 0) internal static (DateTime time, decimal value) CalcTimeWindowAverageValue(DateTime[] timestamps, decimal[] values, int window, int shift = 0)
{ {
var sum = values[values.Length - 1 - shift]; var sum = values[values.Length - 1 - shift];
var count = 1; var count = 1m;
var startTime = timestamps[timestamps.Length - 1 - shift]; var startTime = timestamps[timestamps.Length - 1 - shift];
for (int i = 2; i < values.Length && startTime - timestamps[values.Length - i - shift] < TimeSpan.FromSeconds(window); i++) for (int i = 2; i < values.Length && startTime - timestamps[values.Length - i - shift] < TimeSpan.FromSeconds(window); i++)
{ {
@ -18,33 +18,44 @@ namespace KLHZ.Trader.Core.Math.Declisions.Utils
return (startTime, sum / count); return (startTime, sum / count);
} }
public static TradingEvent CheckByWindowAverageMean(DateTime[] timestamps, float[] prices, int size, float meanfullStep = 3f) public static TradingEvent CheckByWindowAverageMean(DateTime[] timestamps, decimal[] prices, int size,int smallWindow, int bigWindow, decimal meanfullStep = 3m)
{ {
var twav15s = new float[size];
var twav120s = new float[size];
var times = new DateTime[size];
var res = TradingEvent.None; var res = TradingEvent.None;
if (timestamps.Length < size)
{
return res;
}
var pricesForFinalComparison = new decimal[size];
var twavss = new decimal[size];
var twavbs = new decimal[size];
var times = new DateTime[size];
for (int shift = 0; shift < size; shift++) for (int shift = 0; shift < size; shift++)
{ {
var twav15 = CalcTimeWindowAverageValue(timestamps, prices, 15, shift); var twavs = CalcTimeWindowAverageValue(timestamps, prices, smallWindow, shift);
var twav120 = CalcTimeWindowAverageValue(timestamps, prices, 120, shift); var twavb = CalcTimeWindowAverageValue(timestamps, prices, bigWindow, shift);
twav15s[size - 1 - shift] = twav15.value; pricesForFinalComparison[size - 1 - shift] = prices[prices.Length - 1 - shift];
twav120s[size - 1 - shift] = twav120.value; twavss[size - 1 - shift] = twavs.value;
times[size - 1 - shift] = twav120.time; twavbs[size - 1 - shift] = twavb.value;
if (System.Math.Abs(twav120.value - prices[prices.Length - 1]) > 3 * meanfullStep) times[size - 1 - shift] = twavb.time;
if (System.Math.Abs(twavb.value - prices[prices.Length - 1]) > 2 * meanfullStep)
{ {
res |= TradingEvent.StopBuy; res |= TradingEvent.StopBuy;
return res; return res;
} }
if (shift > 0) if (shift > 0)
{ {
var i1 = size - 1 - shift;
var i2 = size - shift;
var isCrossing = Lines.IsLinesCrossing( var isCrossing = Lines.IsLinesCrossing(
times[size - 1 - shift], times[i1],
times[size - 2 - shift], times[i2],
twav15s[size - 1 - shift], twavss[i1],
twav15s[size - 2 - shift], twavss[i2],
twav120s[size - 1 - shift], twavbs[i1],
twav120s[size - 2 - shift]); twavbs[i2]);
if (shift == 1 && !isCrossing) //если нет пересечения скользящих средний с окном 120 и 15 секунд между if (shift == 1 && !isCrossing) //если нет пересечения скользящих средний с окном 120 и 15 секунд между
//текущей и предыдущей точкой - можно не продолжать выполнение. //текущей и предыдущей точкой - можно не продолжать выполнение.
{ {
@ -53,9 +64,9 @@ namespace KLHZ.Trader.Core.Math.Declisions.Utils
if (shift > 1 && isCrossing) if (shift > 1 && isCrossing)
{ {
// если фильтрация окном 120 наползает на окно 15 сверху, потенциальное время открытия лонга и закрытия шорта // если фильтрация окном 120 наползает на окно 15 сверху, потенциальное время открытия лонга и закрытия шорта
if (twav120s[size - 1] <= twav15s[size - 1] && twav120s[size - 2] > twav15s[size - 2]) if (twavbs[size - 1] <= twavss[size - 1] && twavbs[size - 2] > twavss[size - 2])
{ {
if (twav15s[size - 1 - shift] - twav15s[size - 1] >= meanfullStep) if (pricesForFinalComparison[size - 1 - shift] - pricesForFinalComparison[size - 1] >= meanfullStep)
{ {
res |= TradingEvent.LongOpen; res |= TradingEvent.LongOpen;
res |= TradingEvent.ShortClose; res |= TradingEvent.ShortClose;
@ -64,9 +75,9 @@ namespace KLHZ.Trader.Core.Math.Declisions.Utils
} }
// если фильтрация окном 15 наползает на окно 120 сверху, потенциальное время закрытия лонга и возможно открытия шорта // если фильтрация окном 15 наползает на окно 120 сверху, потенциальное время закрытия лонга и возможно открытия шорта
if (twav15s[size - 1] <= twav120s[size - 1] && twav15s[size - 2] > twav120s[size - 2]) if (twavss[size - 1] <= twavbs[size - 1] && twavss[size - 2] > twavbs[size - 2])
{ {
if (twav15s[size - 1 - shift] - twav15s[size - 1] <= -meanfullStep) if (pricesForFinalComparison[size - 1 - shift] - pricesForFinalComparison[size - 1] <= -meanfullStep)
{ {
res |= TradingEvent.LongClose; res |= TradingEvent.LongClose;
res |= TradingEvent.ShortOpen; res |= TradingEvent.ShortOpen;

View File

@ -21,8 +21,8 @@ namespace KLHZ.Trader.Core.Math.Declisions.Utils
var lastPriceTime = times[times.Length - 1]; var lastPriceTime = times[times.Length - 1];
var intervalEnd = lastPriceTime - timeShift; var intervalEnd = lastPriceTime - timeShift;
var intervalStart = intervalEnd - timeSpan; var intervalStart = intervalEnd - timeSpan;
var max = float.MinValue; var max = decimal.MinValue;
var min = float.MaxValue; var min = decimal.MaxValue;
var intervaEndIndex = -1; var intervaEndIndex = -1;
var intervaStartIndex = -1; var intervaStartIndex = -1;
@ -69,18 +69,18 @@ namespace KLHZ.Trader.Core.Math.Declisions.Utils
return res; return res;
} }
internal static bool CheckStable(this PeriodPricesInfoDto data, float meanfullDiff) internal static bool CheckStable(this PeriodPricesInfoDto data, decimal meanfullDiff)
{ {
meanfullDiff = System.Math.Abs(meanfullDiff); meanfullDiff = System.Math.Abs(meanfullDiff);
return data.Success && System.Math.Abs(data.PeriodDiff) < 1.5 * meanfullDiff && System.Math.Abs(data.PeriodMax - data.PeriodMin) < 2 * 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, float 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); 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, float meanfullDiff) internal static bool CheckFalling(this PeriodPricesInfoDto data, decimal meanfullDiff)
{ {
meanfullDiff = -meanfullDiff; meanfullDiff = -meanfullDiff;
return meanfullDiff < 0 && data.Success && data.PeriodDiff < meanfullDiff && System.Math.Abs(data.PeriodMax - data.PeriodMin) < 3 * System.Math.Abs(data.PeriodDiff); return meanfullDiff < 0 && data.Success && data.PeriodDiff < meanfullDiff && System.Math.Abs(data.PeriodMax - data.PeriodMin) < 3 * System.Math.Abs(data.PeriodDiff);
@ -88,20 +88,20 @@ namespace KLHZ.Trader.Core.Math.Declisions.Utils
internal static float CalcTrendRelationAbs(PeriodPricesInfoDto first, PeriodPricesInfoDto second) internal static float CalcTrendRelationAbs(PeriodPricesInfoDto first, PeriodPricesInfoDto second)
{ {
var k1 = System.Math.Abs(first.PeriodDiff) / System.Math.Abs(first.Period.TotalSeconds); var k1 = System.Math.Abs(first.PeriodDiff) / System.Math.Abs((decimal)first.Period.TotalSeconds);
var k2 = System.Math.Abs(second.PeriodDiff) / System.Math.Abs(second.Period.TotalSeconds); var k2 = System.Math.Abs(second.PeriodDiff) / System.Math.Abs((decimal)second.Period.TotalSeconds);
if (k2 == 0 && k1 != 0) return 1000; if (k2 == 0 && k1 != 0) return 1000;
return (float)(k1 / k2); return (float)(k1 / k2);
} }
internal static float CalcTrendRelationAbs(TwoPeriodsResultDto data) internal static float CalcTrendRelationAbs(TwoPeriodsResultDto data)
{ {
var k1 = System.Math.Abs(data.DiffStart) / System.Math.Abs(data.PeriodStart.TotalSeconds); var k1 = System.Math.Abs(data.DiffStart) / System.Math.Abs((decimal)data.PeriodStart.TotalSeconds);
var k2 = System.Math.Abs(data.DiffEnd) / System.Math.Abs(data.PeriodEnd.TotalSeconds); var k2 = System.Math.Abs(data.DiffEnd) / System.Math.Abs((decimal)data.PeriodEnd.TotalSeconds);
if (k2 == 0 && k1 != 0) return 1000; if (k2 == 0 && k1 != 0) return 1000;
return (float)(k1 / k2); return (float)(k1 / k2);
} }
internal static bool CheckDowntrendEnding(this IPriceHistoryCacheUnit unit, TimeSpan firstPeriod, TimeSpan secondPeriod, float meanfullDiff) internal static bool CheckDowntrendEnding(this IPriceHistoryCacheUnit unit, TimeSpan firstPeriod, TimeSpan secondPeriod, decimal meanfullDiff)
{ {
var totalDiff = unit.GetPriceDiffForTimeSpan(TimeSpan.Zero, firstPeriod + secondPeriod); var totalDiff = unit.GetPriceDiffForTimeSpan(TimeSpan.Zero, firstPeriod + secondPeriod);
var startDiff = unit.GetPriceDiffForTimeSpan(secondPeriod, firstPeriod); var startDiff = unit.GetPriceDiffForTimeSpan(secondPeriod, firstPeriod);
@ -121,7 +121,7 @@ namespace KLHZ.Trader.Core.Math.Declisions.Utils
return res; return res;
} }
internal static bool CheckUptrendEnding(this IPriceHistoryCacheUnit unit, TimeSpan firstPeriod, TimeSpan secondPeriod, float meanfullDiff) internal static bool CheckUptrendEnding(this IPriceHistoryCacheUnit unit, TimeSpan firstPeriod, TimeSpan secondPeriod, decimal meanfullDiff)
{ {
var totalDiff = unit.GetPriceDiffForTimeSpan(TimeSpan.Zero, firstPeriod + secondPeriod); var totalDiff = unit.GetPriceDiffForTimeSpan(TimeSpan.Zero, firstPeriod + secondPeriod);
var startDiff = unit.GetPriceDiffForTimeSpan(secondPeriod, firstPeriod); var startDiff = unit.GetPriceDiffForTimeSpan(secondPeriod, firstPeriod);
@ -141,7 +141,7 @@ namespace KLHZ.Trader.Core.Math.Declisions.Utils
return res; return res;
} }
internal static bool CheckDowntrendStarting(this PriceHistoryCacheUnit unit, TimeSpan firstPeriod, TimeSpan secondPeriod, float meanfullDiff) internal static bool CheckDowntrendStarting(this PriceHistoryCacheUnit unit, TimeSpan firstPeriod, TimeSpan secondPeriod, decimal meanfullDiff)
{ {
var totalDiff = unit.GetPriceDiffForTimeSpan(TimeSpan.Zero, firstPeriod + secondPeriod); var totalDiff = unit.GetPriceDiffForTimeSpan(TimeSpan.Zero, firstPeriod + secondPeriod);
var startDiff = unit.GetPriceDiffForTimeSpan(secondPeriod, firstPeriod); var startDiff = unit.GetPriceDiffForTimeSpan(secondPeriod, firstPeriod);
@ -156,7 +156,7 @@ namespace KLHZ.Trader.Core.Math.Declisions.Utils
return totalDiff.Success && (isStartStable || isStartGrows) && isEndFalls && trendRelation >= 2; return totalDiff.Success && (isStartStable || isStartGrows) && isEndFalls && trendRelation >= 2;
} }
internal static bool CheckUptrendStarting(this PriceHistoryCacheUnit unit, TimeSpan firstPeriod, TimeSpan secondPeriod, float meanfullDiff) internal static bool CheckUptrendStarting(this PriceHistoryCacheUnit unit, TimeSpan firstPeriod, TimeSpan secondPeriod, decimal meanfullDiff)
{ {
var totalDiff = unit.GetPriceDiffForTimeSpan(TimeSpan.Zero, firstPeriod + secondPeriod); var totalDiff = unit.GetPriceDiffForTimeSpan(TimeSpan.Zero, firstPeriod + secondPeriod);
var startDiff = unit.GetPriceDiffForTimeSpan(secondPeriod, firstPeriod); var startDiff = unit.GetPriceDiffForTimeSpan(secondPeriod, firstPeriod);
@ -185,7 +185,7 @@ namespace KLHZ.Trader.Core.Math.Declisions.Utils
return res; return res;
} }
internal static TwoPeriodsResultDto GetTwoPeriodsProcessingData(this (DateTime[] timestamps, float[] prices) data, TimeSpan shift, int shiftPointsStart, int shiftPointsEnd, TimeSpan firstPeriod, float meanfullDiff) 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 res = new TwoPeriodsResultDto(success: false, 0, 0, 0, 0, 0, TimeSpan.Zero, TimeSpan.Zero);
var time = data.timestamps; var time = data.timestamps;
@ -222,12 +222,12 @@ namespace KLHZ.Trader.Core.Math.Declisions.Utils
return res; return res;
} }
public static bool CheckLongClose(this IPriceHistoryCacheUnit unit, TimeSpan firstPeriod, TimeSpan secondPeriod, float meanfullDiff, int pointsStart, int pointsEnd) public static bool CheckLongClose(this IPriceHistoryCacheUnit unit, TimeSpan firstPeriod, TimeSpan secondPeriod, decimal meanfullDiff, int pointsStart, int pointsEnd)
{ {
var data = unit.GetData().Result; var data = unit.GetData().Result;
var periodStat = data.GetTwoPeriodsProcessingData(secondPeriod, pointsStart, pointsEnd, firstPeriod, meanfullDiff); var periodStat = data.GetTwoPeriodsProcessingData(secondPeriod, pointsStart, pointsEnd, firstPeriod, meanfullDiff);
var trendRelation = CalcTrendRelationAbs(periodStat); var trendRelation = CalcTrendRelationAbs(periodStat);
var isStartOk = periodStat.Success && periodStat.DiffStart > 0 && periodStat.DiffStart > 1.5 * meanfullDiff; var isStartOk = periodStat.Success && periodStat.DiffStart > 0 && periodStat.DiffStart > 1.5m * meanfullDiff;
var isEndOk = periodStat.Success && periodStat.DiffEnd < meanfullDiff; var isEndOk = periodStat.Success && periodStat.DiffEnd < meanfullDiff;
if (isEndOk) if (isEndOk)
@ -247,7 +247,7 @@ namespace KLHZ.Trader.Core.Math.Declisions.Utils
return isStartOk && isEndOk && data.prices[periodStat.End] - data.prices[periodStat.Start] >= meanfullDiff; return isStartOk && isEndOk && data.prices[periodStat.End] - data.prices[periodStat.Start] >= meanfullDiff;
} }
internal static bool CheckUptrendStarting2(this IPriceHistoryCacheUnit unit, TimeSpan firstPeriod, TimeSpan secondPeriod, float meanfullDiff) internal static bool CheckUptrendStarting2(this IPriceHistoryCacheUnit unit, TimeSpan firstPeriod, TimeSpan secondPeriod, decimal meanfullDiff)
{ {
var data = unit.GetData().Result; var data = unit.GetData().Result;
var periodStat = data.GetTwoPeriodsProcessingData(secondPeriod, 15, 2, firstPeriod, meanfullDiff); var periodStat = data.GetTwoPeriodsProcessingData(secondPeriod, 15, 2, firstPeriod, meanfullDiff);
@ -272,7 +272,7 @@ namespace KLHZ.Trader.Core.Math.Declisions.Utils
return isStartOk && isEndOk; return isStartOk && isEndOk;
} }
internal static bool _CheckUptrendStarting2(this IPriceHistoryCacheUnit unit, TimeSpan firstPeriod, TimeSpan secondPeriod, float meanfullDiff) internal static bool _CheckUptrendStarting2(this IPriceHistoryCacheUnit unit, TimeSpan firstPeriod, TimeSpan secondPeriod, decimal meanfullDiff)
{ {
var data = unit.GetData().Result; var data = unit.GetData().Result;
var periodStat = data.GetTwoPeriodsProcessingData(secondPeriod, 15, 1, firstPeriod, meanfullDiff); var periodStat = data.GetTwoPeriodsProcessingData(secondPeriod, 15, 1, firstPeriod, meanfullDiff);
@ -298,7 +298,7 @@ namespace KLHZ.Trader.Core.Math.Declisions.Utils
} }
public static bool CheckLongOpen(this IPriceHistoryCacheUnit unit, TimeSpan firstPeriod, TimeSpan secondPeriod, float meanfullDiff, int pointsStart, int pointsEnd) public static bool CheckLongOpen(this IPriceHistoryCacheUnit unit, TimeSpan firstPeriod, TimeSpan secondPeriod, decimal meanfullDiff, int pointsStart, int pointsEnd)
{ {
var data = unit.GetData().Result; var data = unit.GetData().Result;
var periodStat = data.GetTwoPeriodsProcessingData(secondPeriod, pointsStart, pointsEnd, firstPeriod, meanfullDiff); var periodStat = data.GetTwoPeriodsProcessingData(secondPeriod, pointsStart, pointsEnd, firstPeriod, meanfullDiff);
@ -325,14 +325,14 @@ namespace KLHZ.Trader.Core.Math.Declisions.Utils
public static TradingEvent Detect(IPriceHistoryCacheUnit data) public static TradingEvent Detect(IPriceHistoryCacheUnit data)
{ {
float meanfullDiff; decimal meanfullDiff;
if (data.Figi == "BBG004730N88") if (data.Figi == "BBG004730N88")
{ {
meanfullDiff = 0.05f; meanfullDiff = 0.05m;
} }
else if (data.Figi == "FUTIMOEXF000") else if (data.Figi == "FUTIMOEXF000")
{ {
meanfullDiff = 1f; meanfullDiff = 1m;
} }
else else
{ {
@ -352,7 +352,7 @@ namespace KLHZ.Trader.Core.Math.Declisions.Utils
} }
//var downtrendEnds = data.CheckDowntrendEnding(TimeSpan.FromSeconds(60), TimeSpan.FromSeconds(15), meanfullDiff); //var downtrendEnds = data.CheckDowntrendEnding(TimeSpan.FromSeconds(60), TimeSpan.FromSeconds(15), meanfullDiff);
var uptrendEnds = data.CheckLongClose(TimeSpan.FromSeconds(15), TimeSpan.FromSeconds(20), meanfullDiff * 1.5f, 8, 8); 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); var uptrendEnds2 = data.CheckLongClose(TimeSpan.FromSeconds(120), TimeSpan.FromSeconds(30), meanfullDiff, 15, 8);
uptrendEnds |= uptrendEnds2; uptrendEnds |= uptrendEnds2;
if (uptrendEnds) if (uptrendEnds)

View File

@ -46,7 +46,7 @@ namespace KLHZ.Trader.Core.Tests
var count = 1; var count = 1;
var figi = "figi"; var figi = "figi";
var hist = GetHistory(count, figi); var hist = GetHistory(count, figi);
var cacheUnit = new PriceHistoryCacheUnit2("", hist); var cacheUnit = new PriceHistoryCacheUnit2(figi, hist);
var data = cacheUnit.GetData().Result; var data = cacheUnit.GetData().Result;
Assert.That(data.prices.Length == count); Assert.That(data.prices.Length == count);
@ -64,7 +64,7 @@ namespace KLHZ.Trader.Core.Tests
var count = 20; var count = 20;
var figi = "figi"; var figi = "figi";
var hist = GetHistory(count, figi); var hist = GetHistory(count, figi);
var cacheUnit = new PriceHistoryCacheUnit2("", hist); var cacheUnit = new PriceHistoryCacheUnit2(figi, hist);
var data = cacheUnit.GetData().Result; var data = cacheUnit.GetData().Result;
Assert.That(data.prices.Length == count); Assert.That(data.prices.Length == count);
@ -83,7 +83,7 @@ namespace KLHZ.Trader.Core.Tests
var count = PriceHistoryCacheUnit.CacheMaxLength; var count = PriceHistoryCacheUnit.CacheMaxLength;
var figi = "figi"; var figi = "figi";
var hist = GetHistory(count, figi); var hist = GetHistory(count, figi);
var cacheUnit = new PriceHistoryCacheUnit2("", hist); var cacheUnit = new PriceHistoryCacheUnit2(figi, hist);
var data = cacheUnit.GetData().Result; var data = cacheUnit.GetData().Result;
Assert.That(data.prices.Length == count); Assert.That(data.prices.Length == count);
@ -103,7 +103,7 @@ namespace KLHZ.Trader.Core.Tests
var count = PriceHistoryCacheUnit.CacheMaxLength + shift; var count = PriceHistoryCacheUnit.CacheMaxLength + shift;
var figi = "figi"; var figi = "figi";
var hist = GetHistory(count, figi); var hist = GetHistory(count, figi);
var cacheUnit = new PriceHistoryCacheUnit2("", hist); var cacheUnit = new PriceHistoryCacheUnit2(figi, hist);
var data = cacheUnit.GetData().Result; var data = cacheUnit.GetData().Result;
Assert.That(data.prices.Length == count - shift); Assert.That(data.prices.Length == count - shift);
@ -127,7 +127,7 @@ namespace KLHZ.Trader.Core.Tests
var count = PriceHistoryCacheUnit.CacheMaxLength + shift; var count = PriceHistoryCacheUnit.CacheMaxLength + shift;
var figi = "figi"; var figi = "figi";
var hist = GetHistory(count, figi); var hist = GetHistory(count, figi);
var cacheUnit = new PriceHistoryCacheUnit2("", hist); var cacheUnit = new PriceHistoryCacheUnit2(figi, hist);
var data = cacheUnit.GetData().Result; var data = cacheUnit.GetData().Result;
Assert.That(data.prices.Length == count - shift); Assert.That(data.prices.Length == count - shift);
@ -151,7 +151,7 @@ namespace KLHZ.Trader.Core.Tests
var count = PriceHistoryCacheUnit.CacheMaxLength + shift; var count = PriceHistoryCacheUnit.CacheMaxLength + shift;
var figi = "figi"; var figi = "figi";
var hist = GetHistory(count, figi); var hist = GetHistory(count, figi);
var cacheUnit = new PriceHistoryCacheUnit2("", hist); var cacheUnit = new PriceHistoryCacheUnit2(figi, hist);
var data = cacheUnit.GetData().Result; var data = cacheUnit.GetData().Result;
Assert.That(data.prices.Length == count - shift); Assert.That(data.prices.Length == count - shift);
@ -175,7 +175,7 @@ namespace KLHZ.Trader.Core.Tests
var count = PriceHistoryCacheUnit.CacheMaxLength; var count = PriceHistoryCacheUnit.CacheMaxLength;
var figi = "figi"; var figi = "figi";
var hist = GetHistory(count, figi); var hist = GetHistory(count, figi);
var cacheUnit = new PriceHistoryCacheUnit2("", hist); var cacheUnit = new PriceHistoryCacheUnit2(figi, hist);
var data = cacheUnit.GetData().Result; var data = cacheUnit.GetData().Result;
Assert.That(data.prices.Length == count); Assert.That(data.prices.Length == count);
@ -192,7 +192,7 @@ namespace KLHZ.Trader.Core.Tests
cacheUnit.AddData(newData1); cacheUnit.AddData(newData1);
var data2 = cacheUnit.GetData().Result; var data2 = cacheUnit.GetData().Result;
Assert.IsTrue(data2.prices[data2.prices.Length - 1] == (float)newData1.Value); Assert.IsTrue(data2.prices[data2.prices.Length - 1] == newData1.Value);
Assert.IsTrue(data2.timestamps[data2.timestamps.Length - 1] == newData1.Time); Assert.IsTrue(data2.timestamps[data2.timestamps.Length - 1] == newData1.Time);
var newData2 = new PriceChange() { Figi = figi, Ticker = figi, Value = 100501, Time = DateTime.UtcNow }; var newData2 = new PriceChange() { Figi = figi, Ticker = figi, Value = 100501, Time = DateTime.UtcNow };
@ -200,7 +200,7 @@ namespace KLHZ.Trader.Core.Tests
cacheUnit.AddData(newData2); cacheUnit.AddData(newData2);
var data3 = cacheUnit.GetData().Result; var data3 = cacheUnit.GetData().Result;
Assert.IsTrue(data3.prices[data3.prices.Length - 1] == (float)newData2.Value); Assert.IsTrue(data3.prices[data3.prices.Length - 1] == newData2.Value);
Assert.IsTrue(data3.timestamps[data3.timestamps.Length - 1] == newData2.Time); Assert.IsTrue(data3.timestamps[data3.timestamps.Length - 1] == newData2.Time);
} }

View File

@ -192,7 +192,7 @@ namespace KLHZ.Trader.Core.Tests
cacheUnit.AddData(newData1); cacheUnit.AddData(newData1);
var data2 = cacheUnit.GetData().Result; var data2 = cacheUnit.GetData().Result;
Assert.IsTrue(data2.prices[data2.prices.Length - 1] == (float)newData1.Value); Assert.IsTrue(data2.prices[data2.prices.Length - 1] == newData1.Value);
Assert.IsTrue(data2.timestamps[data2.timestamps.Length - 1] == newData1.Time); Assert.IsTrue(data2.timestamps[data2.timestamps.Length - 1] == newData1.Time);
var newData2 = new PriceChange() { Figi = figi, Ticker = figi, Value = 100501, Time = DateTime.UtcNow }; var newData2 = new PriceChange() { Figi = figi, Ticker = figi, Value = 100501, Time = DateTime.UtcNow };
@ -200,7 +200,7 @@ namespace KLHZ.Trader.Core.Tests
cacheUnit.AddData(newData2); cacheUnit.AddData(newData2);
var data3 = cacheUnit.GetData().Result; var data3 = cacheUnit.GetData().Result;
Assert.IsTrue(data3.prices[data3.prices.Length - 1] == (float)newData2.Value); Assert.IsTrue(data3.prices[data3.prices.Length - 1] == newData2.Value);
Assert.IsTrue(data3.timestamps[data3.timestamps.Length - 1] == newData2.Time); Assert.IsTrue(data3.timestamps[data3.timestamps.Length - 1] == newData2.Time);
} }
} }

View File

@ -6,7 +6,7 @@ namespace KLHZ.Trader.Core.Tests
{ {
public class HistoryProcessingInstrumentsTests public class HistoryProcessingInstrumentsTests
{ {
private static PriceChange[] GetHistory(int count, string figi, DateTime startDt, float startValue, float step) private static PriceChange[] GetHistory(int count, string figi, DateTime startDt, decimal startValue, decimal step)
{ {
var res = new PriceChange[count]; var res = new PriceChange[count];
if (count != 0) if (count != 0)
@ -21,7 +21,7 @@ namespace KLHZ.Trader.Core.Tests
Ticker = figi + "_ticker", Ticker = figi + "_ticker",
Id = i, Id = i,
Time = startDt, Time = startDt,
Value = (decimal)startValue, Value = startValue,
}; };
} }
} }
@ -68,7 +68,7 @@ namespace KLHZ.Trader.Core.Tests
var figi = "figi"; var figi = "figi";
var startDate = new DateTime(2020, 1, 1, 1, 0, 0, DateTimeKind.Utc); var startDate = new DateTime(2020, 1, 1, 1, 0, 0, DateTimeKind.Utc);
var count = 100; var count = 100;
var step = 0.5f; var step = 0.5m;
var startValue = 10; var startValue = 10;
var unit = new PriceHistoryCacheUnit(figi, GetHistory(count, figi, startDate, startValue, step)); var unit = new PriceHistoryCacheUnit(figi, GetHistory(count, figi, startDate, startValue, step));
@ -102,7 +102,7 @@ namespace KLHZ.Trader.Core.Tests
var figi = "figi"; var figi = "figi";
var startDate = new DateTime(2020, 1, 1, 1, 0, 0, DateTimeKind.Utc); var startDate = new DateTime(2020, 1, 1, 1, 0, 0, DateTimeKind.Utc);
var count = 100; var count = 100;
var step = 0.5f; var step = 0.5m;
var startValue = 10; var startValue = 10;
var unit = new PriceHistoryCacheUnit(figi, GetHistory(count, figi, startDate, startValue, step)); var unit = new PriceHistoryCacheUnit(figi, GetHistory(count, figi, startDate, startValue, step));
@ -137,7 +137,7 @@ namespace KLHZ.Trader.Core.Tests
var figi = "figi"; var figi = "figi";
var startDate = new DateTime(2020, 1, 1, 1, 0, 0, DateTimeKind.Utc); var startDate = new DateTime(2020, 1, 1, 1, 0, 0, DateTimeKind.Utc);
var count = 100; var count = 100;
var step = -0.5f; var step = -0.5m;
var startValue = 10; var startValue = 10;
var unit = new PriceHistoryCacheUnit(figi, GetHistory(count, figi, startDate, startValue, step)); var unit = new PriceHistoryCacheUnit(figi, GetHistory(count, figi, startDate, startValue, step));
@ -172,7 +172,7 @@ namespace KLHZ.Trader.Core.Tests
var figi = "figi"; var figi = "figi";
var startDate = new DateTime(2020, 1, 1, 1, 0, 0, DateTimeKind.Utc); var startDate = new DateTime(2020, 1, 1, 1, 0, 0, DateTimeKind.Utc);
var count = 100; var count = 100;
var step = -0.5f; var step = -0.5m;
var startValue = 10; var startValue = 10;
var unit = new PriceHistoryCacheUnit(figi, GetHistory(count, figi, startDate, startValue, step)); var unit = new PriceHistoryCacheUnit(figi, GetHistory(count, figi, startDate, startValue, step));
@ -207,7 +207,7 @@ namespace KLHZ.Trader.Core.Tests
var figi = "figi"; var figi = "figi";
var startDate = new DateTime(2020, 1, 1, 1, 0, 0, DateTimeKind.Utc); var startDate = new DateTime(2020, 1, 1, 1, 0, 0, DateTimeKind.Utc);
var count = 100; var count = 100;
var step = -0.5f; var step = -0.5m;
var startValue = 10; var startValue = 10;
var unit = new PriceHistoryCacheUnit(figi, GetHistory(count, figi, startDate, startValue, step)); var unit = new PriceHistoryCacheUnit(figi, GetHistory(count, figi, startDate, startValue, step));

View File

@ -10,11 +10,11 @@ namespace KLHZ.Trader.Core.Tests
var time2 = DateTime.UtcNow; var time2 = DateTime.UtcNow;
var time1 = time2.AddSeconds(-20); var time1 = time2.AddSeconds(-20);
var val1_1 = 0.5f; var val1_1 = 0.5m;
var val1_2 = -0.5f; var val1_2 = -0.5m;
var val2_1 = -0.5f; var val2_1 = -0.5m;
var val2_2 = 0.5f; var val2_2 = 0.5m;
Assert.IsTrue(Lines.IsLinesCrossing(time1, time2, val1_1, val1_2, val2_1, val2_2)); Assert.IsTrue(Lines.IsLinesCrossing(time1, time2, val1_1, val1_2, val2_1, val2_2));
} }
@ -25,11 +25,11 @@ namespace KLHZ.Trader.Core.Tests
var time2 = DateTime.UtcNow; var time2 = DateTime.UtcNow;
var time1 = time2.AddSeconds(-20); var time1 = time2.AddSeconds(-20);
var val1_1 = 0.5f; var val1_1 = 0.5m;
var val1_2 = -0.5f; var val1_2 = -0.5m;
var val2_1 = 0.5f; var val2_1 = 0.5m;
var val2_2 = -0.5f; var val2_2 = -0.5m;
Assert.IsFalse(Lines.IsLinesCrossing(time1, time2, val1_1, val1_2, val2_1, val2_2)); Assert.IsFalse(Lines.IsLinesCrossing(time1, time2, val1_1, val1_2, val2_1, val2_2));
} }

View File

@ -142,14 +142,10 @@ namespace KLHZ.Trader.Core.Exchange.Services
{ {
SubscribeOrderBookRequest = bookRequest SubscribeOrderBookRequest = bookRequest
}); });
using var context = await _dbContextFactory.CreateDbContextAsync();
context.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking;
var pricesBuffer = new List<PriceChange>(); var pricesBuffer = new List<PriceChange>();
var orderbookItemsBuffer = new List<OrderbookItem>(); var orderbookItemsBuffer = new List<OrderbookItem>();
var tradesBuffer = new List<InstrumentTrade>(); var tradesBuffer = new List<InstrumentTrade>();
var lastWriteOrderbooks = DateTime.UtcNow;
var lastWriteTrades = DateTime.UtcNow;
var lastWritePrices = DateTime.UtcNow;
var lastWrite = DateTime.UtcNow; var lastWrite = DateTime.UtcNow;
await foreach (var response in stream.ResponseStream.ReadAllAsync()) await foreach (var response in stream.ResponseStream.ReadAllAsync())
{ {
@ -214,25 +210,34 @@ namespace KLHZ.Trader.Core.Exchange.Services
await _eventBus.Broadcast(message); await _eventBus.Broadcast(message);
} }
if (orderbookItemsBuffer.Count + pricesBuffer.Count + tradesBuffer.Count > 1000 || (DateTime.UtcNow - lastWrite).TotalSeconds > 10) if (orderbookItemsBuffer.Count + pricesBuffer.Count + tradesBuffer.Count > 0 || (DateTime.UtcNow - lastWrite).TotalSeconds > 10)
{ {
lastWrite = DateTime.UtcNow; try
if (orderbookItemsBuffer.Count > 0)
{ {
await context.OrderbookItems.AddRangeAsync(orderbookItemsBuffer); using var context = await _dbContextFactory.CreateDbContextAsync();
orderbookItemsBuffer.Clear(); context.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking;
lastWrite = DateTime.UtcNow;
if (orderbookItemsBuffer.Count > 0)
{
await context.OrderbookItems.AddRangeAsync(orderbookItemsBuffer);
orderbookItemsBuffer.Clear();
}
if (pricesBuffer.Count > 0)
{
await context.PriceChanges.AddRangeAsync(pricesBuffer);
pricesBuffer.Clear();
}
if (tradesBuffer.Count > 0)
{
await context.InstrumentTrades.AddRangeAsync(tradesBuffer);
tradesBuffer.Clear();
}
await context.SaveChangesAsync();
} }
if (pricesBuffer.Count > 0) catch (Exception ex)
{ {
await context.PriceChanges.AddRangeAsync(pricesBuffer); _logger.LogError(ex, "Ошибка при сохранении данных биржи.");
pricesBuffer.Clear();
} }
if (tradesBuffer.Count > 0)
{
await context.InstrumentTrades.AddRangeAsync(tradesBuffer);
tradesBuffer.Clear();
}
await context.SaveChangesAsync();
} }
} }
} }

View File

@ -98,7 +98,6 @@ namespace KLHZ.Trader.Core.Exchange.Services
_dataBus.AddChannel(nameof(Trader), _ordersbookChannel); _dataBus.AddChannel(nameof(Trader), _ordersbookChannel);
_ = ProcessPrices(); _ = ProcessPrices();
_ = ProcessOrdersbooks(); _ = ProcessOrdersbooks();
_ = BackgroundWorker();
} }
private async Task InitStops() private async Task InitStops()
@ -119,86 +118,126 @@ namespace KLHZ.Trader.Core.Exchange.Services
while (await _pricesChannel.Reader.WaitToReadAsync()) while (await _pricesChannel.Reader.WaitToReadAsync())
{ {
var message = await _pricesChannel.Reader.ReadAsync(); var message = await _pricesChannel.Reader.ReadAsync();
//if (_tradingInstrumentsFigis.Contains(message.Figi)) if (_tradingInstrumentsFigis.Contains(message.Figi))
//{ {
// if (_historyCash.TryGetValue(message.Figi, out var unit)) if (_historyCash.TryGetValue(message.Figi, out var unit))
// { {
// await unit.AddData(message); await unit.AddData(message);
// } }
// else else
// { {
// unit = new PriceHistoryCacheUnit2(message.Figi, message); unit = new PriceHistoryCacheUnit2(message.Figi, message);
// _historyCash.TryAdd(message.Figi, unit); _historyCash.TryAdd(message.Figi, unit);
// } }
// var data = await unit.GetData(); try
// var declisionsForSave = new List<Declision>(); {
// if (message.Figi == "FUTIMOEXF000") var data = await unit.GetData();
// { var declisionsForSave = new List<Declision>();
// var result = MovingAverage.CheckByWindowAverageMean(data.timestamps, data.prices, 100, 3f); if (message.Figi == "FUTIMOEXF000")
// if ((result & TradingEvent.StopBuy) == TradingEvent.StopBuy) {
// { if (unit.Length < 100)
// var stopTo = DateTime.UtcNow.AddMinutes(_buyStopLength); {
// BuyStops.AddOrUpdate(message.Figi, stopTo, (k, v) => stopTo); continue;
// declisionsForSave.Add(new Declision() }
// {
// AccountId = string.Empty,
// Figi = message.Figi,
// Ticker = message.Ticker,
// Price = message.Value,
// Time = message.IsHistoricalData ? message.Time : DateTime.UtcNow,
// Action = DeclisionTradeAction.StopBuy,
// });
// }
// if ((result & TradingEvent.LongOpen) == TradingEvent.LongOpen
// && !BuyStops.TryGetValue(message.Figi, out _))
// {
// var stopTo = DateTime.UtcNow.AddMinutes(_buyStopLength);
// BuyStops.AddOrUpdate(message.Figi, stopTo, (k, v) => stopTo);
// declisionsForSave.Add(new Declision()
// {
// AccountId = string.Empty,
// Figi = message.Figi,
// Ticker = message.Ticker,
// Price = message.Value,
// Time = message.IsHistoricalData ? message.Time : DateTime.UtcNow,
// Action = DeclisionTradeAction.OpenLong,
// });
// }
// if ((result & TradingEvent.LongClose) == TradingEvent.LongClose) var result = MovingAverage.CheckByWindowAverageMean(data.timestamps, data.prices, 100,15,120);
// { if ((result & TradingEvent.StopBuy) == TradingEvent.StopBuy)
// declisionsForSave.Add(new Declision() {
// { var stopTo = (message.IsHistoricalData?message.Time: DateTime.UtcNow).AddMinutes(_buyStopLength);
// AccountId = string.Empty, BuyStops.AddOrUpdate(message.Figi, stopTo, (k, v) => stopTo);
// Figi = message.Figi, declisionsForSave.Add(new Declision()
// Ticker = message.Ticker, {
// Price = message.Value, AccountId = string.Empty,
// Time = message.IsHistoricalData ? message.Time : DateTime.UtcNow, Figi = message.Figi,
// Action = DeclisionTradeAction.CloseLong, Ticker = message.Ticker,
// }); Price = message.Value,
// } Time = message.IsHistoricalData ? message.Time : DateTime.UtcNow,
Action = DeclisionTradeAction.StopBuy,
});
}
// if ((result & TradingEvent.ShortOpen) == TradingEvent.ShortOpen && (unit.AsksCount/ unit.BidsCount>2 )) if ((result & TradingEvent.LongOpen) == TradingEvent.LongOpen
// { && ((unit.BidsCount / unit.AsksCount) > 0.5m))
// declisionsForSave.Add(new Declision() {
// { if (BuyStops.TryGetValue(message.Figi, out var dt))
// AccountId = string.Empty, {
// Figi = message.Figi, if (dt > (message.IsHistoricalData ? message.Time : DateTime.UtcNow))
// Ticker = message.Ticker, {
// Price = message.Value, continue;
// Time = message.IsHistoricalData ? message.Time : DateTime.UtcNow, }
// Action = DeclisionTradeAction.OpenShort, else
// }); {
// } BuyStops.TryRemove(message.Figi, out _);
}
}
// using var context = await _dbContextFactory.CreateDbContextAsync(); declisionsForSave.Add(new Declision()
// context.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking; {
AccountId = string.Empty,
Figi = message.Figi,
Ticker = message.Ticker,
Price = message.Value,
Time = message.IsHistoricalData ? message.Time : DateTime.UtcNow,
Action = DeclisionTradeAction.OpenLong,
});
}
// await context.AddRangeAsync(declisionsForSave); if ((result & TradingEvent.LongClose) == TradingEvent.LongClose)
// await context.SaveChangesAsync(); {
// } declisionsForSave.Add(new Declision()
//} {
AccountId = string.Empty,
Figi = message.Figi,
Ticker = message.Ticker,
Price = message.Value,
Time = message.IsHistoricalData ? message.Time : DateTime.UtcNow,
Action = DeclisionTradeAction.CloseLong,
});
}
if ((result & TradingEvent.ShortOpen) == TradingEvent.ShortOpen && (unit.BidsCount / unit.AsksCount < 2))
{
declisionsForSave.Add(new Declision()
{
AccountId = string.Empty,
Figi = message.Figi,
Ticker = message.Ticker,
Price = message.Value,
Time = message.IsHistoricalData ? message.Time : DateTime.UtcNow,
Action = DeclisionTradeAction.OpenShort,
});
}
if ((result & TradingEvent.ShortClose) == TradingEvent.ShortClose)
{
declisionsForSave.Add(new Declision()
{
AccountId = string.Empty,
Figi = message.Figi,
Ticker = message.Ticker,
Price = message.Value,
Time = message.IsHistoricalData ? message.Time : DateTime.UtcNow,
Action = DeclisionTradeAction.CloseShort,
});
}
if (declisionsForSave.Count > 0)
{
using var context = await _dbContextFactory.CreateDbContextAsync();
context.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking;
await context.AddRangeAsync(declisionsForSave);
await context.SaveChangesAsync();
declisionsForSave.Clear();
}
}
}
catch (Exception ex)
{
}
}
} }
} }
@ -216,27 +255,6 @@ namespace KLHZ.Trader.Core.Exchange.Services
} }
} }
private async Task BackgroundWorker()
{
var keysForRemove = new List<string>();
while (!_cts.IsCancellationRequested)
{
var time = DateTime.UtcNow;
foreach (var kvp in BuyStops)
{
if (kvp.Value > time)
{
keysForRemove.Add(kvp.Key);
}
}
foreach (var key in keysForRemove)
{
BuyStops.TryRemove(key, out _);
}
await Task.Delay(10000);
}
}
public Task StopAsync(CancellationToken cancellationToken) public Task StopAsync(CancellationToken cancellationToken)
{ {
_cts.Cancel(); _cts.Cancel();