Доработка модуля решений
test / deploy_trader_prod (push) Successful in 49s Details

main
vlad zverzhkhovskiy 2025-09-03 14:32:40 +03:00
parent d045f9b082
commit d15281f67e
5 changed files with 145 additions and 77 deletions

View File

@ -18,78 +18,86 @@ namespace KLHZ.Trader.Core.Math.Declisions.Utils
return (startTime, sum / count); return (startTime, sum / count);
} }
public static TradingEvent CheckByWindowAverageMean(DateTime[] timestamps, decimal[] prices, int size, int smallWindow, int bigWindow, decimal meanfullStep = 3m) public static (TradingEvent events, decimal bigWindowAv, decimal smallWindowAv) CheckByWindowAverageMean(DateTime[] timestamps, decimal[] prices, int size, int smallWindow, int bigWindow, decimal meanfullStep = 3m)
{ {
var res = TradingEvent.None; var res = TradingEvent.None;
if (timestamps.Length < size) var bigWindowAv = 0m;
var smallWindowAv = 0m;
try
{ {
return res; var pricesForFinalComparison = new decimal[size];
} var twavss = new decimal[size];
var pricesForFinalComparison = new decimal[size]; var twavbs = new decimal[size];
var twavss = new decimal[size]; var times = new DateTime[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 twavs = CalcTimeWindowAverageValue(timestamps, prices, smallWindow, shift);
var twavb = CalcTimeWindowAverageValue(timestamps, prices, bigWindow, shift);
pricesForFinalComparison[size - 1 - shift] = prices[prices.Length - 1 - shift];
twavss[size - 1 - shift] = twavs.value;
twavbs[size - 1 - shift] = twavb.value;
times[size - 1 - shift] = twavb.time;
if (System.Math.Abs(twavb.value - prices[prices.Length - 1]) > 2 * meanfullStep)
{ {
res |= TradingEvent.StopBuy; var twavs = CalcTimeWindowAverageValue(timestamps, prices, smallWindow, shift);
return res; var twavb = CalcTimeWindowAverageValue(timestamps, prices, bigWindow, shift);
} pricesForFinalComparison[size - 1 - shift] = prices[prices.Length - 1 - shift];
if (shift > 0) if (shift == 0)
{
var i1 = size - 1 - shift;
var i2 = size - shift;
var isCrossing = Lines.IsLinesCrossing(
times[i1],
times[i2],
twavss[i1],
twavss[i2],
twavbs[i1],
twavbs[i2]);
if (shift == 1 && !isCrossing) //если нет пересечения скользящих средний с окном 120 и 15 секунд между
//текущей и предыдущей точкой - можно не продолжать выполнение.
{ {
break; bigWindowAv = twavb.value;
smallWindowAv = twavs.value;
} }
if (shift > 1 && isCrossing) twavss[size - 1 - shift] = twavs.value;
twavbs[size - 1 - shift] = twavb.value;
times[size - 1 - shift] = twavb.time;
if (System.Math.Abs(twavb.value - prices[prices.Length - 1]) > 2 * meanfullStep)
{ {
// если фильтрация окном 120 наползает на окно 15 сверху, потенциальное время открытия лонга и закрытия шорта res |= TradingEvent.StopBuy;
if (twavbs[size - 1] <= twavss[size - 1] && twavbs[size - 2] > twavss[size - 2]) return (res, bigWindowAv, smallWindowAv);
{ }
if (pricesForFinalComparison[size - 1 - shift] - pricesForFinalComparison[size - 1] >= meanfullStep) if (shift > 0)
{ {
res |= TradingEvent.LongOpen; var i1 = size - 1 - shift;
res |= TradingEvent.ShortClose; var i2 = size - shift;
break; var isCrossing = Lines.IsLinesCrossing(
} times[i1],
} times[i2],
twavss[i1],
twavss[i2],
twavbs[i1],
twavbs[i2]);
// если фильтрация окном 15 наползает на окно 120 сверху, потенциальное время закрытия лонга и возможно открытия шорта if (shift == 1 && !isCrossing) //если нет пересечения скользящих средний с окном 120 и 15 секунд между
if (twavss[size - 1] <= twavbs[size - 1] && twavss[size - 2] > twavbs[size - 2]) //текущей и предыдущей точкой - можно не продолжать выполнение.
{ {
if (pricesForFinalComparison[size - 1 - shift] - pricesForFinalComparison[size - 1] <= -meanfullStep) break;
}
if (shift > 1 && isCrossing)
{
// если фильтрация окном 120 наползает на окно 15 сверху, потенциальное время открытия лонга и закрытия шорта
if (twavbs[size - 1] <= twavss[size - 1] && twavbs[size - 2] > twavss[size - 2])
{ {
res |= TradingEvent.LongClose; if (pricesForFinalComparison[size - 1 - shift] - pricesForFinalComparison[size - 1] >= meanfullStep)
res |= TradingEvent.ShortOpen; {
break; res |= TradingEvent.LongOpen;
res |= TradingEvent.ShortClose;
break;
}
}
// если фильтрация окном 15 наползает на окно 120 сверху, потенциальное время закрытия лонга и возможно открытия шорта
if (twavss[size - 1] <= twavbs[size - 1] && twavss[size - 2] > twavbs[size - 2])
{
if (pricesForFinalComparison[size - 1 - shift] - pricesForFinalComparison[size - 1] <= -meanfullStep)
{
res |= TradingEvent.LongClose;
res |= TradingEvent.ShortOpen;
break;
}
} }
} }
} }
} }
} }
catch (Exception ex)
{
return res; }
return (res, bigWindowAv, smallWindowAv);
} }
} }
} }

View File

@ -23,6 +23,10 @@ namespace KLHZ.Trader.Core.DataLayer.Entities.Declisions
[Column("price")] [Column("price")]
public decimal Price { get; set; } public decimal Price { get; set; }
[Column("value")]
public decimal? Value { get; set; }
[Column("action")] [Column("action")]
public DeclisionTradeAction Action { get; set; } public DeclisionTradeAction Action { get; set; }
} }

View File

@ -7,6 +7,7 @@ using KLHZ.Trader.Core.Contracts.Messaging.Interfaces;
using KLHZ.Trader.Core.DataLayer; using KLHZ.Trader.Core.DataLayer;
using KLHZ.Trader.Core.DataLayer.Entities.Declisions; using KLHZ.Trader.Core.DataLayer.Entities.Declisions;
using KLHZ.Trader.Core.DataLayer.Entities.Declisions.Enums; using KLHZ.Trader.Core.DataLayer.Entities.Declisions.Enums;
using KLHZ.Trader.Core.DataLayer.Entities.Prices;
using KLHZ.Trader.Core.Exchange.Extentions; using KLHZ.Trader.Core.Exchange.Extentions;
using KLHZ.Trader.Core.Exchange.Models; using KLHZ.Trader.Core.Exchange.Models;
using KLHZ.Trader.Core.Math.Declisions.Services.Cache; using KLHZ.Trader.Core.Math.Declisions.Services.Cache;
@ -115,6 +116,8 @@ namespace KLHZ.Trader.Core.Exchange.Services
private async Task ProcessPrices() private async Task ProcessPrices()
{ {
var declisionsForSave = new List<Declision>();
var processedPrices = new List<ProcessedPrice>();
while (await _pricesChannel.Reader.WaitToReadAsync()) while (await _pricesChannel.Reader.WaitToReadAsync())
{ {
var message = await _pricesChannel.Reader.ReadAsync(); var message = await _pricesChannel.Reader.ReadAsync();
@ -132,7 +135,7 @@ namespace KLHZ.Trader.Core.Exchange.Services
try try
{ {
var data = await unit.GetData(); var data = await unit.GetData();
var declisionsForSave = new List<Declision>();
if (message.Figi == "FUTIMOEXF000") if (message.Figi == "FUTIMOEXF000")
{ {
if (unit.Length < 100) if (unit.Length < 100)
@ -140,9 +143,58 @@ namespace KLHZ.Trader.Core.Exchange.Services
continue; continue;
} }
if (BuyStops.TryGetValue(message.Figi, out var dt))
{
if (dt > (message.IsHistoricalData ? message.Time : DateTime.UtcNow))
{
continue;
}
else
{
BuyStops.TryRemove(message.Figi, out _);
}
}
if ((unit.BidsCount / unit.AsksCount) < 0.5m || (unit.BidsCount / unit.AsksCount) > 2m)
{
var stopTo = (message.IsHistoricalData ? message.Time : DateTime.UtcNow).AddMinutes(3);
BuyStops.AddOrUpdate(message.Figi, stopTo, (k, v) => stopTo);
declisionsForSave.Add(new Declision()
{
AccountId = string.Empty,
Figi = message.Figi,
Ticker = message.Ticker,
Price = message.Value,
Value = 3,
Time = message.IsHistoricalData ? message.Time : DateTime.UtcNow,
Action = DeclisionTradeAction.StopBuy,
});
}
var result = MovingAverage.CheckByWindowAverageMean(data.timestamps, data.prices, 100, 15, 120); var result = MovingAverage.CheckByWindowAverageMean(data.timestamps, data.prices, 100, 15, 120);
if ((result & TradingEvent.StopBuy) == TradingEvent.StopBuy) if (result.bigWindowAv != 0)
{
var priceb = new ProcessedPrice()
{
Figi = message.Figi,
Ticker = message.Ticker,
Processor = nameof(Trader) + "_big",
Time = message.Time,
Value = result.bigWindowAv,
};
var prices = new ProcessedPrice()
{
Figi = message.Figi,
Ticker = message.Ticker,
Processor = nameof(Trader) + "_small",
Time = message.Time,
Value = result.smallWindowAv,
};
processedPrices.Add(priceb);
processedPrices.Add(prices);
}
if ((result.events & TradingEvent.StopBuy) == TradingEvent.StopBuy)
{ {
var stopTo = (message.IsHistoricalData ? message.Time : DateTime.UtcNow).AddMinutes(_buyStopLength); var stopTo = (message.IsHistoricalData ? message.Time : DateTime.UtcNow).AddMinutes(_buyStopLength);
BuyStops.AddOrUpdate(message.Figi, stopTo, (k, v) => stopTo); BuyStops.AddOrUpdate(message.Figi, stopTo, (k, v) => stopTo);
@ -152,26 +204,15 @@ namespace KLHZ.Trader.Core.Exchange.Services
Figi = message.Figi, Figi = message.Figi,
Ticker = message.Ticker, Ticker = message.Ticker,
Price = message.Value, Price = message.Value,
Value = (decimal)_buyStopLength,
Time = message.IsHistoricalData ? message.Time : DateTime.UtcNow, Time = message.IsHistoricalData ? message.Time : DateTime.UtcNow,
Action = DeclisionTradeAction.StopBuy, Action = DeclisionTradeAction.StopBuy,
}); });
} }
if ((result & TradingEvent.LongOpen) == TradingEvent.LongOpen if ((result.events & TradingEvent.LongOpen) == TradingEvent.LongOpen
&& ((unit.BidsCount / unit.AsksCount) > 0.5m)) && ((unit.BidsCount / unit.AsksCount) > 0.5m))
{ {
if (BuyStops.TryGetValue(message.Figi, out var dt))
{
if (dt > (message.IsHistoricalData ? message.Time : DateTime.UtcNow))
{
continue;
}
else
{
BuyStops.TryRemove(message.Figi, out _);
}
}
declisionsForSave.Add(new Declision() declisionsForSave.Add(new Declision()
{ {
AccountId = string.Empty, AccountId = string.Empty,
@ -183,7 +224,7 @@ namespace KLHZ.Trader.Core.Exchange.Services
}); });
} }
if ((result & TradingEvent.LongClose) == TradingEvent.LongClose) if ((result.events & TradingEvent.LongClose) == TradingEvent.LongClose)
{ {
declisionsForSave.Add(new Declision() declisionsForSave.Add(new Declision()
{ {
@ -196,7 +237,7 @@ namespace KLHZ.Trader.Core.Exchange.Services
}); });
} }
if ((result & TradingEvent.ShortOpen) == TradingEvent.ShortOpen && (unit.BidsCount / unit.AsksCount < 2)) if ((result.events & TradingEvent.ShortOpen) == TradingEvent.ShortOpen && (unit.BidsCount / unit.AsksCount < 2))
{ {
declisionsForSave.Add(new Declision() declisionsForSave.Add(new Declision()
{ {
@ -209,7 +250,7 @@ namespace KLHZ.Trader.Core.Exchange.Services
}); });
} }
if ((result & TradingEvent.ShortClose) == TradingEvent.ShortClose) if ((result.events & TradingEvent.ShortClose) == TradingEvent.ShortClose)
{ {
declisionsForSave.Add(new Declision() declisionsForSave.Add(new Declision()
{ {
@ -222,14 +263,23 @@ namespace KLHZ.Trader.Core.Exchange.Services
}); });
} }
if (declisionsForSave.Count > 0) if ((!message.IsHistoricalData && (processedPrices.Count > 0 || declisionsForSave.Count > 0))
|| (message.IsHistoricalData && ((processedPrices.Count + declisionsForSave.Count > 10000) || _pricesChannel.Reader.Count == 0)))
{ {
using var context = await _dbContextFactory.CreateDbContextAsync(); using var context = await _dbContextFactory.CreateDbContextAsync();
context.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking; context.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking;
await context.AddRangeAsync(declisionsForSave); if (processedPrices.Count > 0)
{
await context.ProcessedPrices.AddRangeAsync(processedPrices);
processedPrices.Clear();
}
if (declisionsForSave.Count > 0)
{
await context.Declisions.AddRangeAsync(declisionsForSave);
declisionsForSave.Clear();
}
await context.SaveChangesAsync(); await context.SaveChangesAsync();
declisionsForSave.Clear();
} }
} }
} }
@ -238,6 +288,11 @@ namespace KLHZ.Trader.Core.Exchange.Services
} }
} }
if (_pricesChannel.Reader.Count == 0)
{
}
} }
} }

View File

@ -0,0 +1 @@
alter table declisions add column value decimal default null;

View File

@ -12,7 +12,7 @@
"ExchangeDataRecievingEnabled": true, "ExchangeDataRecievingEnabled": true,
"Token": "", "Token": "",
"ManagingAccountNamePatterns": [ "автотрейд 1" ], "ManagingAccountNamePatterns": [ "автотрейд 1" ],
"DataRecievingInstrumentsFigis": [ "BBG004730N88", "FUTIMOEXF000", "FUTGMKN09250", "FUTBR1025000" ], "DataRecievingInstrumentsFigis": [ "BBG004730N88", "FUTIMOEXF000", "FUTGMKN09250", "FUTBR1025000", "FUTNG0925000" ],
"TradingInstrumentsFigis": [ "FUTIMOEXF000" ], "TradingInstrumentsFigis": [ "FUTIMOEXF000" ],
"FutureComission": 0.0025, "FutureComission": 0.0025,
"ShareComission": 0.0004, "ShareComission": 0.0004,