восстановление получения данных о ценах и сделках
test / deploy_trader_prod (push) Successful in 4m33s
Details
test / deploy_trader_prod (push) Successful in 4m33s
Details
parent
8edb4351dd
commit
270e807591
|
@ -1,16 +0,0 @@
|
|||
namespace KLHZ.Trader.Core.Contracts.Declisions.Dtos
|
||||
{
|
||||
public readonly struct TradingEventsDto
|
||||
{
|
||||
public readonly bool LongClose;
|
||||
public readonly bool LongOpen;
|
||||
|
||||
public TradingEventsDto(bool longClose, bool longOpen)
|
||||
{
|
||||
LongClose = longClose;
|
||||
LongOpen = longOpen;
|
||||
}
|
||||
|
||||
public readonly static TradingEventsDto Empty = new TradingEventsDto(false, false);
|
||||
}
|
||||
}
|
|
@ -9,7 +9,7 @@ namespace KLHZ.Trader.Core.Contracts.Declisions.Interfaces
|
|||
public ValueTask AddData(INewPrice priceChange);
|
||||
public ValueTask<(DateTime[] timestamps, float[] prices)> GetData();
|
||||
public ValueTask AddOrderbook(IOrderbook orderbook);
|
||||
public long AsksCount { get; }
|
||||
public long BidsCount { get; }
|
||||
public decimal AsksCount { get; }
|
||||
public decimal BidsCount { get; }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,9 +0,0 @@
|
|||
using KLHZ.Trader.Core.Contracts.Declisions.Dtos.Enums;
|
||||
|
||||
namespace KLHZ.Trader.Core.Contracts.Declisions.Interfaces
|
||||
{
|
||||
public interface ITradingEventsDetector
|
||||
{
|
||||
public ValueTask<TradingEvent> Detect(IPriceHistoryCacheUnit unit);
|
||||
}
|
||||
}
|
|
@ -20,8 +20,8 @@ namespace KLHZ.Trader.Core.Math.Declisions.Services.Cache
|
|||
}
|
||||
}
|
||||
|
||||
public long AsksCount => 1;
|
||||
public long BidsCount => 1;
|
||||
public decimal AsksCount => 1;
|
||||
public decimal BidsCount => 1;
|
||||
|
||||
private readonly object _locker = new();
|
||||
private readonly float[] Prices = new float[CacheMaxLength];
|
||||
|
|
|
@ -21,7 +21,7 @@ namespace KLHZ.Trader.Core.Math.Declisions.Services.Cache
|
|||
}
|
||||
}
|
||||
|
||||
public long AsksCount
|
||||
public decimal AsksCount
|
||||
{
|
||||
get
|
||||
{
|
||||
|
@ -32,7 +32,7 @@ namespace KLHZ.Trader.Core.Math.Declisions.Services.Cache
|
|||
}
|
||||
}
|
||||
|
||||
public long BidsCount
|
||||
public decimal BidsCount
|
||||
{
|
||||
get
|
||||
{
|
||||
|
|
|
@ -1,14 +0,0 @@
|
|||
using KLHZ.Trader.Core.Contracts.Declisions.Dtos.Enums;
|
||||
using KLHZ.Trader.Core.Contracts.Declisions.Interfaces;
|
||||
using KLHZ.Trader.Core.Math.Declisions.Utils;
|
||||
|
||||
namespace KLHZ.Trader.Core.Math.Declisions.Services.EventsDetection
|
||||
{
|
||||
public class IntervalsTradingEventsDetector : ITradingEventsDetector
|
||||
{
|
||||
public ValueTask<TradingEvent> Detect(IPriceHistoryCacheUnit unit)
|
||||
{
|
||||
return ValueTask.FromResult(TwoPeriods.Detect(unit));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
using KLHZ.Trader.Core.Contracts.Declisions.Dtos;
|
||||
using KLHZ.Trader.Core.Contracts.Declisions.Dtos.Enums;
|
||||
using KLHZ.Trader.Core.Math.Common;
|
||||
|
||||
namespace KLHZ.Trader.Core.Math.Declisions.Utils
|
||||
|
@ -18,12 +18,12 @@ namespace KLHZ.Trader.Core.Math.Declisions.Utils
|
|||
return (startTime, sum / count);
|
||||
}
|
||||
|
||||
public static TradingEventsDto CheckByWindowAverageMean(DateTime[] timestamps, float[] prices, int size, float meanfullStep = 3f)
|
||||
public static TradingEvent CheckByWindowAverageMean(DateTime[] timestamps, float[] prices, int size, float meanfullStep = 3f)
|
||||
{
|
||||
var twav15s = new float[size];
|
||||
var twav120s = new float[size];
|
||||
var times = new DateTime[size];
|
||||
|
||||
var res = TradingEvent.None;
|
||||
for (int shift = 0; shift < size; shift++)
|
||||
{
|
||||
var twav15 = CalcTimeWindowAverageValue(timestamps, prices, 15, shift);
|
||||
|
@ -31,7 +31,11 @@ namespace KLHZ.Trader.Core.Math.Declisions.Utils
|
|||
twav15s[size - 1 - shift] = twav15.value;
|
||||
twav120s[size - 1 - shift] = twav120.value;
|
||||
times[size - 1 - shift] = twav120.time;
|
||||
|
||||
if (System.Math.Abs(twav120.value - prices[prices.Length - 1]) > 3 * meanfullStep)
|
||||
{
|
||||
res |= TradingEvent.StopBuy;
|
||||
return res;
|
||||
}
|
||||
if (shift > 0)
|
||||
{
|
||||
var isCrossing = Lines.IsLinesCrossing(
|
||||
|
@ -53,7 +57,9 @@ namespace KLHZ.Trader.Core.Math.Declisions.Utils
|
|||
{
|
||||
if (twav15s[size - 1 - shift] - twav15s[size - 1] >= meanfullStep)
|
||||
{
|
||||
return new TradingEventsDto(false, true);
|
||||
res |= TradingEvent.LongOpen;
|
||||
res |= TradingEvent.ShortClose;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -62,14 +68,16 @@ namespace KLHZ.Trader.Core.Math.Declisions.Utils
|
|||
{
|
||||
if (twav15s[size - 1 - shift] - twav15s[size - 1] <= -meanfullStep)
|
||||
{
|
||||
return new TradingEventsDto(true, false);
|
||||
res |= TradingEvent.LongClose;
|
||||
res |= TradingEvent.ShortOpen;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return new TradingEventsDto(false, false);
|
||||
return res;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
public enum DeclisionTradeAction
|
||||
{
|
||||
Unknown = 0,
|
||||
StopBuy = 1,
|
||||
OpenLong = 100,
|
||||
CloseLong = 200,
|
||||
OpenShort = 300,
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
public class ExchangeConfig
|
||||
{
|
||||
public bool ExchangeDataRecievingEnabled { get; set; }
|
||||
public decimal StopBuyLengthMinuts { get; set; }
|
||||
public decimal FutureComission { get; set; }
|
||||
public decimal ShareComission { get; set; }
|
||||
public decimal AccountCashPart { get; set; }
|
||||
|
|
|
@ -132,10 +132,16 @@ namespace KLHZ.Trader.Core.Exchange.Services
|
|||
await stream.RequestStream.WriteAsync(new MarketDataRequest
|
||||
{
|
||||
SubscribeLastPriceRequest = request,
|
||||
SubscribeTradesRequest = tradesRequest,
|
||||
SubscribeOrderBookRequest = bookRequest
|
||||
});
|
||||
|
||||
await stream.RequestStream.WriteAsync(new MarketDataRequest
|
||||
{
|
||||
SubscribeTradesRequest = tradesRequest,
|
||||
});
|
||||
await stream.RequestStream.WriteAsync(new MarketDataRequest
|
||||
{
|
||||
SubscribeOrderBookRequest = bookRequest
|
||||
});
|
||||
using var context = await _dbContextFactory.CreateDbContextAsync();
|
||||
context.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking;
|
||||
var pricesBuffer = new List<PriceChange>();
|
||||
|
|
|
@ -10,6 +10,7 @@ using KLHZ.Trader.Core.DataLayer.Entities.Declisions.Enums;
|
|||
using KLHZ.Trader.Core.Exchange.Extentions;
|
||||
using KLHZ.Trader.Core.Exchange.Models;
|
||||
using KLHZ.Trader.Core.Math.Declisions.Services.Cache;
|
||||
using KLHZ.Trader.Core.Math.Declisions.Utils;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
|
@ -29,25 +30,26 @@ namespace KLHZ.Trader.Core.Exchange.Services
|
|||
private readonly IDataBus _dataBus;
|
||||
private readonly BotModeSwitcher _botModeSwitcher;
|
||||
private readonly IDbContextFactory<TraderDbContext> _dbContextFactory;
|
||||
private readonly ConcurrentDictionary<string, DateTime> BuyStops = new();
|
||||
private readonly ConcurrentDictionary<string, ManagedAccount> Accounts = new();
|
||||
private readonly ConcurrentDictionary<string, IPriceHistoryCacheUnit> _historyCash = new();
|
||||
private readonly ITradingEventsDetector _tradingEventsDetector;
|
||||
private readonly ILogger<Trader> _logger;
|
||||
|
||||
|
||||
private readonly double _buyStopLength;
|
||||
private readonly decimal _futureComission;
|
||||
private readonly decimal _shareComission;
|
||||
private readonly decimal _accountCashPart;
|
||||
private readonly decimal _accountCashPartFutures;
|
||||
private readonly decimal _defaultBuyPartOfAccount;
|
||||
private readonly string[] _managedAccountsNamePatterns = [];
|
||||
private readonly string[] _tradingInstrumentsFigis = [];
|
||||
|
||||
private readonly Channel<INewPrice> _pricesChannel = Channel.CreateUnbounded<INewPrice>();
|
||||
private readonly Channel<IOrderbook> _ordersbookChannel = Channel.CreateUnbounded<IOrderbook>();
|
||||
|
||||
private readonly CancellationTokenSource _cts = new();
|
||||
public Trader(
|
||||
ILogger<Trader> logger,
|
||||
ITradingEventsDetector tradingEventsDetector,
|
||||
BotModeSwitcher botModeSwitcher,
|
||||
IServiceProvider provider,
|
||||
IOptions<ExchangeConfig> options,
|
||||
|
@ -56,7 +58,6 @@ namespace KLHZ.Trader.Core.Exchange.Services
|
|||
InvestApiClient investApiClient)
|
||||
{
|
||||
_logger = logger;
|
||||
_tradingEventsDetector = tradingEventsDetector;
|
||||
_botModeSwitcher = botModeSwitcher;
|
||||
_dataBus = dataBus;
|
||||
_provider = provider;
|
||||
|
@ -68,10 +69,13 @@ namespace KLHZ.Trader.Core.Exchange.Services
|
|||
_accountCashPart = options.Value.AccountCashPart;
|
||||
_accountCashPartFutures = options.Value.AccountCashPartFutures;
|
||||
_defaultBuyPartOfAccount = options.Value.DefaultBuyPartOfAccount;
|
||||
_tradingInstrumentsFigis = options.Value.TradingInstrumentsFigis;
|
||||
_buyStopLength = (double)options.Value.StopBuyLengthMinuts;
|
||||
}
|
||||
|
||||
public async Task StartAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
//await InitStops();
|
||||
var accounts = await _investApiClient.GetAccounts(_managedAccountsNamePatterns);
|
||||
var accountsList = new List<ManagedAccount>();
|
||||
int i = 0;
|
||||
|
@ -94,6 +98,20 @@ namespace KLHZ.Trader.Core.Exchange.Services
|
|||
_dataBus.AddChannel(nameof(Trader), _ordersbookChannel);
|
||||
_ = ProcessPrices();
|
||||
_ = ProcessOrdersbooks();
|
||||
_ = BackgroundWorker();
|
||||
}
|
||||
|
||||
private async Task InitStops()
|
||||
{
|
||||
using var context = await _dbContextFactory.CreateDbContextAsync();
|
||||
context.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking;
|
||||
var dt = DateTime.UtcNow.AddMinutes(-_buyStopLength);
|
||||
var stops = await context.Declisions.Where(d => d.Time > dt && d.Action == DeclisionTradeAction.StopBuy).ToArrayAsync();
|
||||
foreach (var stop in stops)
|
||||
{
|
||||
var time = stop.Time.AddMinutes(_buyStopLength);
|
||||
BuyStops.TryAdd(stop.Figi, time);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task ProcessPrices()
|
||||
|
@ -101,54 +119,86 @@ namespace KLHZ.Trader.Core.Exchange.Services
|
|||
while (await _pricesChannel.Reader.WaitToReadAsync())
|
||||
{
|
||||
var message = await _pricesChannel.Reader.ReadAsync();
|
||||
if (_historyCash.TryGetValue(message.Figi, out var data))
|
||||
{
|
||||
await data.AddData(message);
|
||||
}
|
||||
else
|
||||
{
|
||||
data = new PriceHistoryCacheUnit2(message.Figi, message);
|
||||
_historyCash.TryAdd(message.Figi, data);
|
||||
}
|
||||
var result = await _tradingEventsDetector.Detect(data);
|
||||
//if (_tradingInstrumentsFigis.Contains(message.Figi))
|
||||
//{
|
||||
// if (_historyCash.TryGetValue(message.Figi, out var unit))
|
||||
// {
|
||||
// await unit.AddData(message);
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// unit = new PriceHistoryCacheUnit2(message.Figi, message);
|
||||
// _historyCash.TryAdd(message.Figi, unit);
|
||||
// }
|
||||
// var data = await unit.GetData();
|
||||
// var declisionsForSave = new List<Declision>();
|
||||
// if (message.Figi == "FUTIMOEXF000")
|
||||
// {
|
||||
// var result = MovingAverage.CheckByWindowAverageMean(data.timestamps, data.prices, 100, 3f);
|
||||
// if ((result & TradingEvent.StopBuy) == TradingEvent.StopBuy)
|
||||
// {
|
||||
// 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.StopBuy,
|
||||
// });
|
||||
// }
|
||||
|
||||
try
|
||||
{
|
||||
if ((result & TradingEvent.LongOpen) == TradingEvent.LongOpen)
|
||||
{
|
||||
using var context = await _dbContextFactory.CreateDbContextAsync();
|
||||
context.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking;
|
||||
await context.Declisions.AddAsync(new Declision()
|
||||
{
|
||||
AccountId = string.Empty,
|
||||
Figi = message.Figi,
|
||||
Ticker = message.Ticker,
|
||||
Price = message.Value,
|
||||
Time = message.IsHistoricalData ? message.Time : DateTime.UtcNow,
|
||||
Action = DeclisionTradeAction.OpenLong,
|
||||
});
|
||||
await context.SaveChangesAsync();
|
||||
}
|
||||
if ((result & TradingEvent.LongClose) == TradingEvent.LongClose)
|
||||
{
|
||||
using var context = await _dbContextFactory.CreateDbContextAsync();
|
||||
context.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking;
|
||||
await context.Declisions.AddAsync(new Declision()
|
||||
{
|
||||
AccountId = string.Empty,
|
||||
Figi = message.Figi,
|
||||
Ticker = message.Ticker,
|
||||
Price = message.Value,
|
||||
Time = message.IsHistoricalData ? message.Time : DateTime.UtcNow,
|
||||
Action = DeclisionTradeAction.CloseLong,
|
||||
});
|
||||
await context.SaveChangesAsync();
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
// 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)
|
||||
// {
|
||||
// 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.AsksCount/ unit.BidsCount>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,
|
||||
// });
|
||||
// }
|
||||
|
||||
// using var context = await _dbContextFactory.CreateDbContextAsync();
|
||||
// context.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking;
|
||||
|
||||
// await context.AddRangeAsync(declisionsForSave);
|
||||
// await context.SaveChangesAsync();
|
||||
// }
|
||||
//}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -166,8 +216,30 @@ 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)
|
||||
{
|
||||
_cts.Cancel();
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,11 +1,9 @@
|
|||
using KLHZ.Trader.Core.Common;
|
||||
using KLHZ.Trader.Core.Common.Messaging.Services;
|
||||
using KLHZ.Trader.Core.Contracts.Declisions.Interfaces;
|
||||
using KLHZ.Trader.Core.Contracts.Messaging.Interfaces;
|
||||
using KLHZ.Trader.Core.DataLayer;
|
||||
using KLHZ.Trader.Core.Exchange;
|
||||
using KLHZ.Trader.Core.Exchange.Services;
|
||||
using KLHZ.Trader.Core.Math.Declisions.Services.EventsDetection;
|
||||
using KLHZ.Trader.Core.TG;
|
||||
using KLHZ.Trader.Core.TG.Services;
|
||||
using KLHZ.Trader.Service.Infrastructure;
|
||||
|
@ -53,7 +51,6 @@ builder.Services.AddHostedService<Trader>();
|
|||
builder.Services.AddSingleton<IUpdateHandler, BotMessagesHandler>();
|
||||
builder.Services.AddSingleton<BotModeSwitcher>();
|
||||
builder.Services.AddSingleton<IDataBus, DataBus>();
|
||||
builder.Services.AddSingleton<ITradingEventsDetector, IntervalsTradingEventsDetector>();
|
||||
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
},
|
||||
"LokiUrl": "",
|
||||
"ExchangeConfig": {
|
||||
"StopBuyLengthMinuts": 20,
|
||||
"ExchangeDataRecievingEnabled": true,
|
||||
"Token": "",
|
||||
"ManagingAccountNamePatterns": [ "автотрейд 1" ],
|
||||
|
|
|
@ -28,6 +28,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "postrgres", "postrgres", "{
|
|||
KLHZ.Trader.Infrastructure\postgres\init.sql = KLHZ.Trader.Infrastructure\postgres\init.sql
|
||||
KLHZ.Trader.Infrastructure\postgres\migration1.sql = KLHZ.Trader.Infrastructure\postgres\migration1.sql
|
||||
KLHZ.Trader.Infrastructure\postgres\migration2.sql = KLHZ.Trader.Infrastructure\postgres\migration2.sql
|
||||
KLHZ.Trader.Infrastructure\postgres\migration3.sql = KLHZ.Trader.Infrastructure\postgres\migration3.sql
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "loki", "loki", "{63D21DAF-FDF0-4F2D-A671-E9E59BB0CA5B}"
|
||||
|
|
Loading…
Reference in New Issue