diff --git a/KLHZ.Trader.Core.Contracts/Declisions/Dtos/CachedValue.cs b/KLHZ.Trader.Core.Contracts/Declisions/Dtos/CachedValue.cs
index 815cc70..52d6872 100644
--- a/KLHZ.Trader.Core.Contracts/Declisions/Dtos/CachedValue.cs
+++ b/KLHZ.Trader.Core.Contracts/Declisions/Dtos/CachedValue.cs
@@ -3,7 +3,7 @@
public class CachedValue
{
public DateTime Time { get; init; }
- public decimal Value { get; init; }
- public decimal Value2 { get; init; }
+ public decimal Count { get; init; }
+ public decimal Price { get; init; }
}
}
diff --git a/KLHZ.Trader.Core.Math/Declisions/Utils/Statistics.cs b/KLHZ.Trader.Core.Math/Declisions/Utils/Statistics.cs
index 6778ea8..850002c 100644
--- a/KLHZ.Trader.Core.Math/Declisions/Utils/Statistics.cs
+++ b/KLHZ.Trader.Core.Math/Declisions/Utils/Statistics.cs
@@ -7,12 +7,12 @@ namespace KLHZ.Trader.Core.Math.Declisions.Utils
public static decimal Mean(this CachedValue[] values)
{
- return values.Sum(x => x.Value) / values.Length;
+ return values.Sum(x => x.Count) / values.Length;
}
public static decimal Mean2(this CachedValue[] values)
{
- return values.Sum(x => x.Value2) / values.Length;
+ return values.Sum(x => x.Price) / values.Length;
}
private static (decimal mean, decimal std) CaclSigma(decimal[] values)
@@ -94,9 +94,9 @@ namespace KLHZ.Trader.Core.Math.Declisions.Utils
{
var tradevolume_diffMean = values.Mean();
var dprice_diffMean = values.Mean2();
- var sum1 = (double)values.Sum(d => (d.Value - tradevolume_diffMean) * (d.Value2 - dprice_diffMean));
- var sum2 = values.Sum(d => (d.Value - tradevolume_diffMean) * (d.Value - tradevolume_diffMean));
- var sum3 = values.Sum(d => (d.Value2 - dprice_diffMean) * (d.Value2 - dprice_diffMean));
+ var sum1 = (double)values.Sum(d => (d.Count - tradevolume_diffMean) * (d.Price - dprice_diffMean));
+ var sum2 = values.Sum(d => (d.Count - tradevolume_diffMean) * (d.Count - tradevolume_diffMean));
+ var sum3 = values.Sum(d => (d.Price - dprice_diffMean) * (d.Price - dprice_diffMean));
if (sum2 != 0 && sum3 != 0)
{
result = (decimal)(sum1 / System.Math.Sqrt((double)(sum2 * sum3)));
diff --git a/KLHZ.Trader.Core/DataLayer/Entities/Trades/Enums/TradeDirection.cs b/KLHZ.Trader.Core/Common/TradeDirection.cs
similarity index 58%
rename from KLHZ.Trader.Core/DataLayer/Entities/Trades/Enums/TradeDirection.cs
rename to KLHZ.Trader.Core/Common/TradeDirection.cs
index 2042e4a..b48ec27 100644
--- a/KLHZ.Trader.Core/DataLayer/Entities/Trades/Enums/TradeDirection.cs
+++ b/KLHZ.Trader.Core/Common/TradeDirection.cs
@@ -1,4 +1,4 @@
-namespace KLHZ.Trader.Core.DataLayer.Entities.Trades.Enums
+namespace KLHZ.Trader.Core.Common
{
public enum TradeDirection
{
diff --git a/KLHZ.Trader.Core/DataLayer/Entities/Trades/Enums/AssetType.cs b/KLHZ.Trader.Core/DataLayer/Entities/Trades/Enums/AssetType.cs
deleted file mode 100644
index 5da2b5a..0000000
--- a/KLHZ.Trader.Core/DataLayer/Entities/Trades/Enums/AssetType.cs
+++ /dev/null
@@ -1,10 +0,0 @@
-namespace KLHZ.Trader.Core.DataLayer.Entities.Trades.Enums
-{
- public enum AssetType
- {
- Unknown = 0,
- Common = 1,
- Future = 2,
- Currency = 3,
- }
-}
diff --git a/KLHZ.Trader.Core/DataLayer/Entities/Trades/Enums/PositionType.cs b/KLHZ.Trader.Core/DataLayer/Entities/Trades/Enums/PositionType.cs
deleted file mode 100644
index 3b90439..0000000
--- a/KLHZ.Trader.Core/DataLayer/Entities/Trades/Enums/PositionType.cs
+++ /dev/null
@@ -1,9 +0,0 @@
-namespace KLHZ.Trader.Core.DataLayer.Entities.Trades.Enums
-{
- public enum PositionType
- {
- Unknown = 0,
- Long = 1,
- Short = 2
- }
-}
diff --git a/KLHZ.Trader.Core/DataLayer/Entities/Trades/Trade.cs b/KLHZ.Trader.Core/DataLayer/Entities/Trades/Trade.cs
deleted file mode 100644
index de797ca..0000000
--- a/KLHZ.Trader.Core/DataLayer/Entities/Trades/Trade.cs
+++ /dev/null
@@ -1,52 +0,0 @@
-using KLHZ.Trader.Core.DataLayer.Entities.Trades.Enums;
-using System.ComponentModel.DataAnnotations.Schema;
-
-namespace KLHZ.Trader.Core.DataLayer.Entities.Trades
-{
- ///
- /// Сделка, совершенная ботом.
- ///
- [Table("trades")]
- public class Trade
- {
- [Column("trade_id")]
- public long Id { get; set; }
-
- [Column("bought_at")]
- public DateTime BoughtAt { get; set; }
-
- [Column("account_id")]
- public required string AccountId { get; set; }
-
- [Column("figi")]
- public required string Figi { get; set; }
-
- [Column("ticker")]
- public required string Ticker { get; set; }
-
- [Column("price")]
-
- public decimal Price { get; set; }
-
- [Column("count")]
- public decimal Count { get; set; }
-
- [Column("count_lots")]
- public decimal CountLots { get; set; }
-
- [Column("archive_status")]
- public int ArchiveStatus { get; set; }
-
- [Column("direction")]
- public TradeDirection Direction { get; set; }
-
- [Column("position_type")]
- public PositionType Position { get; set; }
-
- [Column("asset_type")]
- public AssetType Asset { get; set; }
-
- [Column("asset_id")]
- public Guid AssetId { get; set; }
- }
-}
diff --git a/KLHZ.Trader.Core/DataLayer/TraderDbContext.cs b/KLHZ.Trader.Core/DataLayer/TraderDbContext.cs
index 245beb5..f8dd9a0 100644
--- a/KLHZ.Trader.Core/DataLayer/TraderDbContext.cs
+++ b/KLHZ.Trader.Core/DataLayer/TraderDbContext.cs
@@ -1,7 +1,6 @@
using KLHZ.Trader.Core.DataLayer.Entities.Declisions;
using KLHZ.Trader.Core.DataLayer.Entities.Orders;
using KLHZ.Trader.Core.DataLayer.Entities.Prices;
-using KLHZ.Trader.Core.DataLayer.Entities.Trades;
using Microsoft.EntityFrameworkCore;
@@ -9,7 +8,6 @@ namespace KLHZ.Trader.Core.DataLayer
{
public class TraderDbContext : DbContext
{
- public DbSet Trades { get; set; }
public DbSet Declisions { get; set; }
public DbSet PriceChanges { get; set; }
public DbSet ProcessedPrices { get; set; }
@@ -23,15 +21,6 @@ namespace KLHZ.Trader.Core.DataLayer
{
modelBuilder.UseSerialColumns();
- modelBuilder.Entity(entity =>
- {
- entity.HasKey(e1 => e1.Id);
- entity.Property(e => e.BoughtAt)
- .HasConversion(
- v => v.ToUniversalTime(),
- v => DateTime.SpecifyKind(v, DateTimeKind.Utc));
- });
-
modelBuilder.Entity(entity =>
{
entity.HasKey(e1 => e1.Id);
diff --git a/KLHZ.Trader.Core/Exchange/Models/AssetsAccounting/DealResult.cs b/KLHZ.Trader.Core/Exchange/Models/AssetsAccounting/DealResult.cs
deleted file mode 100644
index 407c400..0000000
--- a/KLHZ.Trader.Core/Exchange/Models/AssetsAccounting/DealResult.cs
+++ /dev/null
@@ -1,12 +0,0 @@
-namespace KLHZ.Trader.Core.Exchange.Models.AssetsAccounting
-{
- public class DealResult
- {
- public required string AccountId { get; set; }
- public required string Figi { get; set; }
- public decimal Price { get; set; }
- public decimal Count { get; set; }
- public bool Success { get; set; }
- public DealDirection Direction { get; set; }
- }
-}
diff --git a/KLHZ.Trader.Core/Exchange/Models/AssetsAccounting/Order.cs b/KLHZ.Trader.Core/Exchange/Models/AssetsAccounting/Order.cs
deleted file mode 100644
index 4beef7c..0000000
--- a/KLHZ.Trader.Core/Exchange/Models/AssetsAccounting/Order.cs
+++ /dev/null
@@ -1,15 +0,0 @@
-namespace KLHZ.Trader.Core.Exchange.Models.AssetsAccounting
-{
- public class Order
- {
- public required string AccountId { get; init; }
- public required string Figi { get; init; }
- public required string Ticker { get; init; }
- public required string OrderId { get; init; }
- public decimal Price { get; init; }
- public long Count { get; init; }
- public DateTime ExpirationTime { get; init; }
- public DateTime OpenDate { get; init; }
- public DealDirection Direction { get; init; }
- }
-}
diff --git a/KLHZ.Trader.Core/Exchange/Models/Configs/ExchangeConfig.cs b/KLHZ.Trader.Core/Exchange/Models/Configs/ExchangeConfig.cs
index 2546973..c467f43 100644
--- a/KLHZ.Trader.Core/Exchange/Models/Configs/ExchangeConfig.cs
+++ b/KLHZ.Trader.Core/Exchange/Models/Configs/ExchangeConfig.cs
@@ -2,16 +2,16 @@
{
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; }
- public decimal AccountCashPartFutures { get; set; }
- public decimal DefaultBuyPartOfAccount { get; set; }
- public string[] DataRecievingInstrumentsFigis { get; set; } = [];
- public string[] TradingInstrumentsFigis { get; set; } = [];
- public string[] ManagingAccountNamePatterns { get; set; } = [];
- public InstrumentSettings[] InstrumentsSettings { get; set; } = [];
+ public bool ExchangeDataRecievingEnabled { get; init; }
+ public decimal StopBuyLengthMinuts { get; init; }
+ public decimal FutureComission { get; init; }
+ public decimal ShareComission { get; init; }
+ public decimal AccountCashPart { get; init; }
+ public decimal AccountCashPartFutures { get; init; }
+ public decimal DefaultBuyPartOfAccount { get; init; }
+ public string[] DataRecievingInstrumentsFigis { get; init; } = [];
+ public string[] TradingInstrumentsFigis { get; init; } = [];
+ public string[] ManagingAccountNamePatterns { get; init; } = [];
+ public InstrumentSettings[] InstrumentsSettings { get; init; } = [];
}
}
diff --git a/KLHZ.Trader.Core/Exchange/Services/ExchangeDataReader.cs b/KLHZ.Trader.Core/Exchange/Services/ExchangeDataReader.cs
index c0a9bb2..dddfb8a 100644
--- a/KLHZ.Trader.Core/Exchange/Services/ExchangeDataReader.cs
+++ b/KLHZ.Trader.Core/Exchange/Services/ExchangeDataReader.cs
@@ -6,7 +6,6 @@ using KLHZ.Trader.Core.DataLayer.Entities.Orders;
using KLHZ.Trader.Core.DataLayer.Entities.Prices;
using KLHZ.Trader.Core.Exchange.Extentions;
using KLHZ.Trader.Core.Exchange.Models.Configs;
-using KLHZ.Trader.Core.Exchange.Utils;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
@@ -156,39 +155,7 @@ namespace KLHZ.Trader.Core.Exchange.Services
Count = response.Trade.Quantity,
};
- //await _tradeDataProvider.AddData(message, TimeSpan.FromHours(7));
await _eventBus.Broadcast(message);
-
- var exchangeState = ExchangeScheduler.GetCurrentState();
- if (exchangeState == Models.Trading.ExchangeState.ClearingTime
- && lastUpdateDict.TryGetValue(message.Figi, out var pri)
- && (DateTime.UtcNow - pri.Time).Minutes > 3)
- {
- var assets = _portfolioWrapper.Accounts.Values.SelectMany(a => a.Assets.Values).Where(a => a.Figi == message.Figi).ToArray();
-
- foreach (var a in assets)
- {
- using var context = await _dbContextFactory.CreateDbContextAsync();
- context.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking;
- await context.Trades.AddAsync(new DataLayer.Entities.Trades.Trade()
- {
- AssetId = a.AssetId,
- AccountId = string.Empty,
- Figi = message.Figi,
- Ticker = string.Empty,
- ArchiveStatus = 0,
- Asset = (KLHZ.Trader.Core.DataLayer.Entities.Trades.Enums.AssetType)(int)a.Type,
- BoughtAt = DateTime.UtcNow,
- Count = 0,
- Direction = a.Count > 0 ? DataLayer.Entities.Trades.Enums.TradeDirection.Buy : DataLayer.Entities.Trades.Enums.TradeDirection.Sell,
- Position = a.Count > 0 ? DataLayer.Entities.Trades.Enums.PositionType.Long : DataLayer.Entities.Trades.Enums.PositionType.Short,
- Price = message.Value,
- });
- await context.SaveChangesAsync();
- }
- }
- lastUpdateDict[message.Figi] = message;
-
pricesBuffer.Add(message);
}
if (response.Orderbook != null)
diff --git a/KLHZ.Trader.Core/Exchange/Services/ManagedAccount.cs b/KLHZ.Trader.Core/Exchange/Services/ManagedAccount.cs
index dc31586..406db63 100644
--- a/KLHZ.Trader.Core/Exchange/Services/ManagedAccount.cs
+++ b/KLHZ.Trader.Core/Exchange/Services/ManagedAccount.cs
@@ -50,13 +50,11 @@ namespace KLHZ.Trader.Core.Exchange.Services
public ImmutableDictionary Assets => GetAssets();
-
private readonly InvestApiClient _investApiClient;
private readonly IDbContextFactory _dbContextFactory;
private readonly ILogger _logger;
private readonly IOptions _options;
-
private readonly Dictionary _assets = new();
private readonly ConcurrentDictionary _usedOrderIds = new();
@@ -140,26 +138,20 @@ namespace KLHZ.Trader.Core.Exchange.Services
using var context = await _dbContextFactory.CreateDbContextAsync();
context.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking;
- var trades = await context.Trades
- .Where(t => t.ArchiveStatus == 0)
- .OrderByDescending(t => t.BoughtAt)
- .ToListAsync();
-
var oldAssets = _assets.ToDictionary();
_assets.Clear();
foreach (var position in portfolio.Positions)
{
oldAssets.TryGetValue(position.Figi, out var oldAsset);
var newAssetId = oldAsset?.AssetId ?? Guid.NewGuid();
- var trade = trades.FirstOrDefault(t => t.Figi == position.Figi && t.AssetId == newAssetId);
var asset = new Asset()
{
AssetId = newAssetId,
AccountId = AccountId,
Figi = position.Figi,
Ticker = position.Ticker,
- BoughtAt = trade?.BoughtAt ?? DateTime.UtcNow,
- BoughtPrice = trade?.Price ?? position.AveragePositionPrice,
+ BoughtAt = oldAsset?.BoughtAt ?? DateTime.UtcNow,
+ BoughtPrice = oldAsset?.BoughtPrice ?? position.AveragePositionPrice,
Type = position.InstrumentType.ParseInstrumentType(),
Position = position.Quantity > 0 ? PositionType.Long : PositionType.Short,
BlockedItems = position.BlockedLots,
diff --git a/KLHZ.Trader.Core/Exchange/Services/Trader.cs b/KLHZ.Trader.Core/Exchange/Services/Trader.cs
index 4f33283..5b397cb 100644
--- a/KLHZ.Trader.Core/Exchange/Services/Trader.cs
+++ b/KLHZ.Trader.Core/Exchange/Services/Trader.cs
@@ -11,7 +11,6 @@ using KLHZ.Trader.Core.Exchange.Interfaces;
using KLHZ.Trader.Core.Exchange.Models.Configs;
using KLHZ.Trader.Core.Exchange.Models.Trading;
using KLHZ.Trader.Core.Exchange.Utils;
-using KLHZ.Trader.Core.Math.Declisions.Dtos.FFT.Enums;
using KLHZ.Trader.Core.Math.Declisions.Utils;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Hosting;
@@ -33,36 +32,17 @@ namespace KLHZ.Trader.Core.Exchange.Services
private readonly IDataBus _dataBus;
private readonly TraderDataProvider _tradeDataProvider;
private readonly PortfolioWrapper _portfolioWrapper;
-
+ private readonly ExchangeConfig _exchangeConfig;
private readonly ILogger _logger;
- private readonly ConcurrentDictionary LastTradingEvents = new();
private readonly ConcurrentDictionary TradingModes = new();
- private readonly ConcurrentDictionary OrderBooks = new();
- private readonly ConcurrentDictionary privces = new();
- private readonly ConcurrentDictionary privcesDiffDiff = new();
- private readonly ConcurrentDictionary privcesDiffDiffPrev = new();
- private readonly ConcurrentDictionary correlations = new();
- private readonly ConcurrentDictionary correlationsPrev = new();
- private readonly ConcurrentDictionary PirsonZeroCrossings = new();
private readonly ConcurrentDictionary DPirsonValues = new();
- private readonly ConcurrentDictionary PricesZeroCrossingsUp = new();
- private readonly ConcurrentDictionary PricesZeroCrossingsDown = new();
-
private readonly ConcurrentDictionary LongOpeningStops = new();
private readonly ConcurrentDictionary ShortOpeningStops = new();
private readonly ConcurrentDictionary LongClosingStops = new();
private readonly ConcurrentDictionary ShortClosingStops = new();
- private readonly ConcurrentDictionary Leverages = new();
-
-
- private readonly decimal _futureComission;
- private readonly decimal _shareComission;
- private readonly decimal _accountCashPart;
- private readonly decimal _accountCashPartFutures;
- private readonly string[] _tradingInstrumentsFigis = [];
private readonly Channel _pricesChannel = Channel.CreateUnbounded();
private readonly Channel _commands = Channel.CreateUnbounded();
@@ -79,20 +59,11 @@ namespace KLHZ.Trader.Core.Exchange.Services
_tradeDataProvider = tradeDataProvider;
_logger = logger;
_dataBus = dataBus;
- _futureComission = options.Value.FutureComission;
- _shareComission = options.Value.ShareComission;
- _accountCashPart = options.Value.AccountCashPart;
- _accountCashPartFutures = options.Value.AccountCashPartFutures;
- _tradingInstrumentsFigis = options.Value.TradingInstrumentsFigis;
- foreach (var f in _tradingInstrumentsFigis)
+ _exchangeConfig = options.Value;
+ foreach (var f in _exchangeConfig.TradingInstrumentsFigis)
{
TradingModes[f] = TradingMode.None;
}
-
- foreach (var lev in options.Value.InstrumentsSettings)
- {
- Leverages.TryAdd(lev.Figi, lev);
- }
}
public Task StartAsync(CancellationToken cancellationToken)
@@ -106,122 +77,6 @@ namespace KLHZ.Trader.Core.Exchange.Services
return Task.CompletedTask;
}
- public async ValueTask<(DateTime[] timestamps, decimal[] prices, bool isFullIntervalExists)> GetData(INewPrice message, TimeSpan? windowSize = null)
- {
- var data2 = await _tradeDataProvider.GetData(message.Figi, windowSize ?? TimeSpan.FromHours(1));
- //if (!data2.isFullIntervalExists)
- //{
- // data2 = await _tradeDataProvider.GetData(message.Figi, TimeSpan.FromHours(0.75));
- //}
- return data2;
- }
-
- private async ValueTask<(decimal smallWindow, decimal bigWindow)> GetWindowsSizes(INewPrice message)
- {
- var fftFull = await _tradeDataProvider.GetFFtResult(message.Figi + "_full");
- if (!fftFull.IsEmpty)
- {
- var harms = fftFull.Harmonics.Skip(1).Take(fftFull.Harmonics.Length - 3).ToArray();
- var sum = harms.Sum(h => h.Magnitude);
- var sumtmp = 0f;
- foreach (var h in harms)
- {
- sumtmp += h.Magnitude;
- if (sumtmp / sum > 0.7f)
- {
- return ((decimal)(h.Period.TotalSeconds / 4), (decimal)(h.Period.TotalSeconds));
- }
- }
- }
- return (30m, 180m);
- }
-
- private async ValueTask CheckHarmonicPosition((DateTime[] timestamps, decimal[] prices, bool isFullIntervalExists) data, INewPrice message)
- {
- var currentTime = message.IsHistoricalData ? message.Time : DateTime.UtcNow;
- var position = ValueAmplitudePosition.None;
- var fft = await _tradeDataProvider.GetFFtResult(message.Figi);
- var fftFull = await _tradeDataProvider.GetFFtResult(message.Figi + "_full");
- //var highFreq = await _tradeDataProvider.GetFFtResult(message.Figi + "_high_freq");
- //var lowFreq = await _tradeDataProvider.GetFFtResult(message.Figi + "_low_freq");
- var step = message.IsHistoricalData ? 40 : 5;
- if (fft.IsEmpty || (currentTime - fft.LastTime).TotalSeconds > step)
- {
- if (data.isFullIntervalExists)
- {
- var interpolatedData = SignalProcessing.InterpolateData(data.timestamps, data.prices, TimeSpan.FromSeconds(5));
- fftFull = FFT.Analyze(interpolatedData.timestamps, interpolatedData.values, message.Figi + "_full", TimeSpan.FromMinutes(2), TimeSpan.FromMinutes(30));
-
- //fft = FFT.ReAnalyze(fftFull, message.Figi, TimeSpan.FromMinutes(10), TimeSpan.FromMinutes(60));
- //highFreq = FFT.ReAnalyze(fftFull, message.Figi + "_low_freq", TimeSpan.FromMinutes(20), TimeSpan.FromMinutes(60));
- //lowFreq = FFT.ReAnalyze(fftFull, message.Figi + "_high_freq", TimeSpan.FromMinutes(3), TimeSpan.FromMinutes(20));
- //var tmp = FFT.GetMainHarmonic(interpolatedData.timestamps, interpolatedData.values, "mainHarm", TimeSpan.FromMinutes(20));
- //await _tradeDataProvider.SetFFtResult(fft);
- await _tradeDataProvider.SetFFtResult(fftFull);
- //await _tradeDataProvider.SetFFtResult(lowFreq);
- //await _tradeDataProvider.SetFFtResult(highFreq);
-
- }
-
- //var highFreqData = await GetData(message, TimeSpan.FromMinutes(120));
-
- //if (highFreqData.isFullIntervalExists)
- //{
- // var interpolatehighFreqData = SignalProcessing.InterpolateData(data.timestamps, data.prices, TimeSpan.FromSeconds(5));
- // highFreq = FFT.Analyze(interpolatehighFreqData.timestamps, interpolatehighFreqData.values, message.Figi + "_high_freq", TimeSpan.FromSeconds(20), TimeSpan.FromMinutes(120));
- // await _tradeDataProvider.SetFFtResult(highFreq);
- //}
- }
-
-
-
- position = FFT.Check(fftFull, message.Time);
- if (position == Math.Declisions.Dtos.FFT.Enums.ValueAmplitudePosition.UpperThen30Decil)
- {
- await LogPrice(message, "upper30percent", message.Value);
- }
- if (position == Math.Declisions.Dtos.FFT.Enums.ValueAmplitudePosition.LowerThenMedianaGrowing)
- {
- await LogPrice(message, "lower30percent", message.Value);
- }
-
-
-
- //var hposition = FFT.CheckExtremums(highFreq, message.Time);
- //if (hposition == Math.Declisions.Dtos.FFT.Enums.ValueAmplitudePosition.UpperThen30Decil)
- //{
- // await LogPrice(message, "high_freq_high", message.Value);
- //}
- //if (hposition == Math.Declisions.Dtos.FFT.Enums.ValueAmplitudePosition.LowerThen30Decil)
- //{
- // await LogPrice(message, "high_freq_low", message.Value);
- //}
-
-
- //var gposition = FFT.CheckSign(highFreq, message.Time);
- //if (gposition == Math.Declisions.Dtos.FFT.Enums.ValueAmplitudePosition.Growing)
- //{
- // await LogPrice(message, "growing", message.Value);
- //}
- //if (gposition == Math.Declisions.Dtos.FFT.Enums.ValueAmplitudePosition.Falling)
- //{
- // await LogPrice(message, "falling", message.Value);
- //}
-
-
- //var lposition = FFT.CheckExtremums(lowFreq, message.Time);
- //if (lposition == Math.Declisions.Dtos.FFT.Enums.ValueAmplitudePosition.UpperThen30Decil)
- //{
- // await LogPrice(message, "low_freq_high", message.Value);
- //}
- //if (lposition == Math.Declisions.Dtos.FFT.Enums.ValueAmplitudePosition.LowerThen30Decil)
- //{
- // await LogPrice(message, "low_freq_low", message.Value);
- //}
-
- return position;
- }
-
private async Task ProcessCommands()
{
while (await _commands.Reader.WaitToReadAsync())
@@ -265,37 +120,10 @@ namespace KLHZ.Trader.Core.Exchange.Services
{
var message = await _orderbooks.Reader.ReadAsync();
await _tradeDataProvider.AddOrderbook(message);
-
- //if (OrderBooks.TryGetValue(message.Figi, out var oldMessage))
- //{
- // if (message.Bids.Length > 0 && oldMessage.Bids.Length>0)
- // {
- // var val = message.Bids[0].Count - oldMessage.Bids[0].Count;
- // await _tradeDataProvider.AddDataTo20SecondsWindowCache(message.Figi, "dbids0", new Contracts.Declisions.Dtos.CachedValue()
- // {
- // Time = message.Time,
- // Value = val
- // });
- // if (val!=0)
- // await LogPrice(message.Figi, message.Ticker, message.Time, val, "bids0");
- // }
- // if (message.Asks.Length > 0 && oldMessage.Asks.Length > 0)
- // {
- // var val = message.Asks[0].Count - oldMessage.Asks[0].Count;
- // await _tradeDataProvider.AddDataTo20SecondsWindowCache(message.Figi, "dasks0", new Contracts.Declisions.Dtos.CachedValue()
- // {
- // Time = message.Time,
- // Value = val
- // });
- // if (val != 0)
- // await LogPrice(message.Figi, message.Ticker, message.Time, val, "asks0");
- // }
-
- //}
- OrderBooks[message.Figi] = message;
}
}
+
private async Task ProcessPrices()
{
var pricesCache1 = new Dictionary>();
@@ -308,107 +136,41 @@ namespace KLHZ.Trader.Core.Exchange.Services
{
continue;
}
- var changeMods = GetInitDict(0);
+ var changeMods = TraderUtils.GetInitDict(0);
try
{
- #region Ускорение обработки исторических данных при отладке
- if (message.Direction == 1)
- {
- if (!pricesCache1.TryGetValue(message.Figi, out var list))
- {
- list = new List();
- pricesCache1[message.Figi] = list;
- }
- list.Add(message);
+ message = TraderUtils.FilterHighFreqValues(message, message.Direction == 1 ? pricesCache1 : pricesCache2);
- if ((list.Last().Time - list.First().Time).TotalSeconds < 0.5)
- {
- list.Add(message);
- continue;
- }
- else
- {
- message = new PriceChange()
- {
- Figi = message.Figi,
- Ticker = message.Ticker,
- Count = message.Count,
- Direction = message.Direction,
- IsHistoricalData = message.IsHistoricalData,
- Time = message.Time,
- Value = list.Sum(l => l.Value) / list.Count
- };
- list.Clear();
- }
- }
- if (message.Direction == 2)
- {
-
- if (!pricesCache2.TryGetValue(message.Figi, out var list))
- {
- list = new List();
- pricesCache2[message.Figi] = list;
- }
- list.Add(message);
-
- if ((list.Last().Time - list.First().Time).TotalSeconds < 0.5)
- {
- list.Add(message);
- continue;
- }
- else
- {
- message = new PriceChange()
- {
- Figi = message.Figi,
- Ticker = message.Ticker,
- Count = message.Count,
- Direction = message.Direction,
- IsHistoricalData = message.IsHistoricalData,
- Time = message.Time,
- Value = list.Sum(l => l.Value) / list.Count
- };
- list.Clear();
- }
- }
-
-
-
-
- #endregion
-
- #region Подсчёт торгового баланса по сберу и IMOEXF
+ #region Добавление данных в кеши.
if (message.Figi == "BBG004730N88" || message.Figi == "FUTIMOEXF000")
{
if (message.Direction == 1)
{
-
-
await _tradeDataProvider.AddDataTo20SecondsWindowCache(message.Figi, "1", new Contracts.Declisions.Dtos.CachedValue()
{
Time = message.Time,
- Value = message.Count,
- Value2 = message.Value,
+ Count = message.Count,
+ Price = message.Value,
});
await _tradeDataProvider.AddDataTo5MinuteWindowCache(message.Figi, Constants._5minBuyCacheKey, new Contracts.Declisions.Dtos.CachedValue()
{
Time = message.Time,
- Value = (decimal)message.Count,
- Value2 = message.Value,
+ Count = (decimal)message.Count,
+ Price = message.Value,
});
await _tradeDataProvider.AddDataTo15MinuteWindowCache(message.Figi, Constants._15minBuyCacheKey, new Contracts.Declisions.Dtos.CachedValue()
{
Time = message.Time,
- Value = (decimal)message.Count,
- Value2 = message.Value,
+ Count = (decimal)message.Count,
+ Price = message.Value,
});
await _tradeDataProvider.AddDataTo1MinuteWindowCache(message.Figi, Constants._1minBuyCacheKey, new Contracts.Declisions.Dtos.CachedValue()
{
Time = message.Time,
- Value = (decimal)message.Count,
- Value2 = message.Value,
+ Count = (decimal)message.Count,
+ Price = message.Value,
});
}
if (message.Direction == 2)
@@ -416,32 +178,32 @@ namespace KLHZ.Trader.Core.Exchange.Services
await _tradeDataProvider.AddDataTo5MinuteWindowCache(message.Figi, Constants._5minSellCacheKey, new Contracts.Declisions.Dtos.CachedValue()
{
Time = message.Time,
- Value = (decimal)message.Count,
- Value2 = message.Value,
+ Count = (decimal)message.Count,
+ Price = message.Value,
});
await _tradeDataProvider.AddDataTo15MinuteWindowCache(message.Figi, Constants._15minSellCacheKey, new Contracts.Declisions.Dtos.CachedValue()
{
Time = message.Time,
- Value = (decimal)message.Count,
- Value2 = message.Value,
+ Count = (decimal)message.Count,
+ Price = message.Value,
});
await _tradeDataProvider.AddDataTo1MinuteWindowCache(message.Figi, Constants._1minSellCacheKey, new Contracts.Declisions.Dtos.CachedValue()
{
Time = message.Time,
- Value = (decimal)message.Count,
- Value2 = message.Value,
+ Count = (decimal)message.Count,
+ Price = message.Value,
});
await _tradeDataProvider.AddDataTo20SecondsWindowCache(message.Figi, "2", new Contracts.Declisions.Dtos.CachedValue()
{
Time = message.Time,
- Value = message.Count,
- Value2 = message.Value,
+ Count = message.Count,
+ Price = message.Value,
});
}
}
#endregion
- if (_tradingInstrumentsFigis.Contains(message.Figi) && (message.Figi == "FUTIMOEXF000" || message.Figi == "BBG004730N88") && message.Direction == 1)
+ if (_exchangeConfig.TradingInstrumentsFigis.Contains(message.Figi) && (message.Figi == "FUTIMOEXF000" || message.Figi == "BBG004730N88") && message.Direction == 1)
{
var smallWindow = TimeSpan.FromSeconds(120);
var bigWindow = TimeSpan.FromSeconds(240);
@@ -454,29 +216,29 @@ namespace KLHZ.Trader.Core.Exchange.Services
var trades = buys.ToList();
trades.AddRange(sells);
var trades2 = trades.OrderBy(t => t.Time).ToArray();
- if (trades2.TryCalcTimeWindowsDiff(bigWindow, smallWindow, v => v.Value, false, out var tradesDiff)
- && buys.TryCalcTimeWindowsDiff(bigWindow, smallWindow, v => v.Value2, true, out var pricesDiff))
+ if (trades2.TryCalcTimeWindowsDiff(bigWindow, smallWindow, v => v.Count, false, out var tradesDiff)
+ && buys.TryCalcTimeWindowsDiff(bigWindow, smallWindow, v => v.Price, true, out var pricesDiff))
{
await LogPrice(message, "privcesDiff", pricesDiff);
await LogPrice(message, "tradevolume_diff", tradesDiff);
await _tradeDataProvider.AddDataTo15MinuteWindowCache(message.Figi, "5min_diff", new Contracts.Declisions.Dtos.CachedValue()
{
Time = message.Time,
- Value = tradesDiff,
- Value2 = pricesDiff,
+ Count = tradesDiff,
+ Price = pricesDiff,
});
var diffs = await _tradeDataProvider.GetDataFrom15MinuteWindowCache(message.Figi, "5min_diff");
- if (diffs.TryCalcTimeWindowsDiff(bigWindow, smallWindow, (c) => c.Value2, true, out var resdp)
- && diffs.TryCalcTimeWindowsDiff(bigWindow, smallWindow, (c) => c.Value, true, out var resv))
+ if (diffs.TryCalcTimeWindowsDiff(bigWindow, smallWindow, (c) => c.Price, true, out var resdp)
+ && diffs.TryCalcTimeWindowsDiff(bigWindow, smallWindow, (c) => c.Count, true, out var resv))
{
await LogPrice(message, "privcesDiffDiff", (decimal)resdp);
await LogPrice(message, "tradevolume_diff_diff", (decimal)resv);
await _tradeDataProvider.AddDataTo15MinuteWindowCache(message.Figi, "5min_diff_diff", new Contracts.Declisions.Dtos.CachedValue()
{
Time = message.Time,
- Value = resv,
- Value2 = resdp,
+ Count = resv,
+ Price = resdp,
});
if (diffs.TryCalcPirsonCorrelation(meanWindow, out var pirson))
{
@@ -484,16 +246,10 @@ namespace KLHZ.Trader.Core.Exchange.Services
await _tradeDataProvider.AddDataTo15MinuteWindowCache(message.Figi, "diffs_pirson", new Contracts.Declisions.Dtos.CachedValue()
{
Time = message.Time,
- Value = (decimal)pirson,
+ Count = (decimal)pirson,
});
- if (pirson < 0)
- {
- //PirsonZeroCrossings["FUTIMOEXF000"] = message.Time;
- PirsonZeroCrossings[message.Figi] = message.Time;
- // await SetEvents(message);
- }
var diffs_pirson = await _tradeDataProvider.GetDataFrom15MinuteWindowCache(message.Figi, "diffs_pirson");
- if (diffs_pirson.TryCalcTimeWindowsDiff(bigWindow, smallWindow, (c) => c.Value, true, out var res))
+ if (diffs_pirson.TryCalcTimeWindowsDiff(bigWindow, smallWindow, (c) => c.Count, true, out var res))
{
await LogPrice(message, "diffs_pirson_diff", (decimal)res);
if (DPirsonValues.TryGetValue(message.Figi, out var olddpirs))
@@ -514,57 +270,7 @@ namespace KLHZ.Trader.Core.Exchange.Services
DPirsonValues[message.Figi] = res;
}
}
-
-
- var diffdiff = await _tradeDataProvider.GetDataFrom15MinuteWindowCache(message.Figi, "5min_diff_diff");
-
-
- //resdp = diffdiff.Where(d => message.Time - d.Time < TimeSpan.FromSeconds(45)).ToArray().Mean2();
-
- if (privcesDiffDiff.TryGetValue(message.Figi, out var priceOld))
- {
- privcesDiffDiffPrev[message.Figi] = priceOld;
- }
- privcesDiffDiff[message.Figi] = pricesDiff;
-
- if (privcesDiffDiff.TryGetValue(message.Figi, out var dprice2)
- && privcesDiffDiffPrev.TryGetValue(message.Figi, out var dprice2_prev))
- {
- if (((dprice2 < 0 && dprice2_prev > 0) || (dprice2 > 0 && dprice2_prev < 0)))
- {
- if (PirsonZeroCrossings.TryGetValue(message.Figi, out var pir)
- && message.Time - pir < TimeSpan.FromSeconds(60))
- {
- if (pricesDiff < 0)
- {
- PricesZeroCrossingsDown["FUTIMOEXF000"] = message.Time;
- //await SetEvents(message);
- await LogPrice(message, "price_diff2_point_short", message.Value);
- }
- if (pricesDiff > 0)
- {
- PricesZeroCrossingsUp["FUTIMOEXF000"] = message.Time;
- //await SetEvents(message);
- await LogPrice(message, "price_diff2_point_long", message.Value);
- }
- }
- }
- }
-
- if (diffdiff.TryCalcPirsonCorrelation(meanWindow, out var pirson2))
- {
- if (correlations.TryGetValue(message.Figi, out var corr))
- {
- correlationsPrev[message.Figi] = corr;
- }
- await LogPrice(message, "diffs2_pirson", (decimal)pirson2);
- correlations[message.Figi] = pirson2;
- }
}
-
-
-
-
}
if (timesCache.TryGetValue(message.Figi, out var dt))
@@ -661,308 +367,6 @@ namespace KLHZ.Trader.Core.Exchange.Services
}
}
-
- //
- private async Task SetEvents(INewPrice message)
- {
- DateTime pz = DateTime.MinValue;
- if (PirsonZeroCrossings.TryGetValue(message.Figi, out var pir))
- {
- if (PricesZeroCrossingsDown.TryGetValue(message.Figi, out pz))
- {
- if (message.Time - pir < TimeSpan.FromSeconds(120) && message.Time - pz < TimeSpan.FromSeconds(120))
- {
- await LogPrice(message, "price_diff2_point_short", message.Value);
- }
- }
- if (PricesZeroCrossingsUp.TryGetValue(message.Figi, out pz))
- {
- if (message.Time - pir < TimeSpan.FromSeconds(120) && message.Time - pz < TimeSpan.FromSeconds(120))
- {
- await LogPrice(message, "price_diff2_point_long", message.Value);
- }
- }
- }
- }
- private async Task> CheckDivergency(DateTime[] timestamps, decimal[] values, INewPrice message)
- {
- var res = GetInitDict(1);
- var time1 = message.Time - TimeSpan.FromMinutes(4);
- var time2 = message.Time - TimeSpan.FromMinutes(2);
-
- var data1 = FFT.TrimValues(timestamps, values, TimeSpan.FromMinutes(4), TimeSpan.FromMinutes(2));
- var data2 = FFT.TrimValues(timestamps, values, TimeSpan.FromMinutes(2), TimeSpan.FromSeconds(-1));
- var p1 = data1.values.Sum() / data1.values.Length;
- var p2 = data2.values.Sum() / data2.values.Length;
- var dp = p2 - p1;
-
- var buys = await _tradeDataProvider.GetDataFrom5MinuteWindowCache(message.Figi, Constants._5minBuyCacheKey);
- var sells = await _tradeDataProvider.GetDataFrom5MinuteWindowCache(message.Figi, Constants._5minSellCacheKey);
-
- var buysOld = buys.Where(b => b.Time < time2 && b.Time >= time1).ToArray();
- var sellsOld = sells.Where(b => b.Time < time2 && b.Time >= time1).ToArray();
- var buysNew = buys.Where(b => b.Time >= time2).ToArray();
- var sellNew = sells.Where(b => b.Time >= time2).ToArray();
- if (buysNew.Length > 0 && buysOld.Length > 0)
- {
- var dpriceNew = buysNew.Sum(b => b.Value);
- var dpriceOld = buysOld.Sum(b => b.Value);
- }
-
-
- return res.ToImmutableDictionary();
- }
-
- private async Task> GetSpeedResultantMods(INewPrice message)
- {
- var res = GetInitDict(1);
- //var blocks = GetInitDict(1);
- var buys5min = await _tradeDataProvider.GetDataFrom15MinuteWindowCache(message.Figi, Constants._15minBuyCacheKey);
- var sells5min = await _tradeDataProvider.GetDataFrom15MinuteWindowCache(message.Figi, Constants._15minSellCacheKey);
- var buysSpeed5min = buys5min.Sum(p => p.Value) / 900;
- var sellsSpeed5min = sells5min.Sum(p => p.Value) / 900;
- var diff5min = buysSpeed5min - sellsSpeed5min;
- await _tradeDataProvider.AddDataTo5MinuteWindowCache(message.Figi, "diff15min", new Contracts.Declisions.Dtos.CachedValue()
- {
- Time = message.Time,
- Value = diff5min,
- });
- await LogPrice(message, "speed_diff_15min", diff5min);
-
-
- var orderBook = _tradeDataProvider.Orderbooks[message.Figi];
- if (orderBook.Asks.Length > 3 && orderBook.Bids.Length > 3)
- {
- var asks = (decimal)(orderBook.Asks[0].Count + orderBook.Asks[1].Count / 2 + orderBook.Asks[2].Count / 4);
- //var asks = (decimal)(orderBook.Asks[0].Count + orderBook.Asks[1].Count + orderBook.Asks[2].Count + orderBook.Asks[3].Count);
- var bids = (decimal)(orderBook.Bids[0].Count + orderBook.Bids[1].Count / 2 + orderBook.Bids[2].Count / 4);
- var asks_lifetime = asks / buysSpeed5min;
- var bids_lifetime = bids / sellsSpeed5min;
- var changeModIndicator = (asks_lifetime - bids_lifetime) / (asks_lifetime + bids_lifetime);
- await LogPrice(message, "asks_lifetime", asks_lifetime);
- await LogPrice(message, "bids_lifetime", bids_lifetime);
-
-
- await _tradeDataProvider.AddDataTo20SecondsWindowCache(message.Figi, "changemode", new Contracts.Declisions.Dtos.CachedValue()
- {
- Time = message.Time,
- Value = changeModIndicator,
- });
-
- var changemodes = await _tradeDataProvider.GetDataFrom20SecondsWindowCache(message.Figi, "changemode");
- if (changemodes.Length > 1)
- {
-
- await LogPrice(message, "changemode", changeModIndicator);
- }
-
-
-
- //var sells20 = await _tradeDataProvider.GetDataFrom20SecondsWindowCache(message.Figi, "2");
- //var buys20 = await _tradeDataProvider.GetDataFrom20SecondsWindowCache(message.Figi, "1");
-
- //if (sells20.Length>0)
- // await LogPrice(message.Figi, message.Ticker, message.Time, sells20.Sum(v => v.Value), "sells20");
- //if (buys20.Length > 0)
- // await LogPrice(message.Figi, message.Ticker, message.Time, buys20.Sum(v => v.Value), "buys20");
- //if (changemodes[changemodes.Length-1].Time - changemodes[0].Time > TimeSpan.FromMinutes(10))
- //{
- // var diffs = SignalProcessing.CalcDiffs(changemodes.Select(c => c.Value).ToArray());
- // var cleareddiffs = Statistics.ClearNSigmaReqursive(diffs,0,3);
- // var max = cleareddiffs.Max(d => System.Math.Abs(d));
- // var o = changemodes[changemodes.Length - 1].Value - changemodes[changemodes.Length - 2].Value;
- // if (System.Math.Abs(o) > max)
- // {
- // o = 2;// System.Math.Sign(o);
- // }
- // else
- // {
- // o= 0;
- // }
- // await LogPrice(message, "result_lifetime_open", o);
- // cleareddiffs = Statistics.ClearNSigmaReqursive(diffs, 0, 10);
- // max = cleareddiffs.Max(d => System.Math.Abs(d));
- // var s = changemodes[changemodes.Length - 1].Value - changemodes[changemodes.Length - 2].Value;
- // if (System.Math.Abs(s) > max)
- // {
- // if (LastTradingEvents.TryGetValue(message.Figi, out var ev))
- // {
- // if ((ev & TradingEvent.DowntrendStart) == TradingEvent.DowntrendStart)
- // {
- // ShortOpeningStops[message.Figi] = message.Time.AddMinutes(10);
- // }
- // if ((ev & TradingEvent.UptrendStart) == TradingEvent.UptrendStart)
- // {
- // LongOpeningStops[message.Figi] = message.Time.AddMinutes(10);
- // }
- // }
- // s = 2;// System.Math.Sign(s);
- // }
- // else
- // {
- // s = 0;
- // }
-
- // await LogPrice(message, "result_lifetime_stop", s);
- //}
-
- }
-
- var cached = await _tradeDataProvider.GetDataFrom5MinuteWindowCache(message.Figi, "diff15min");
- decimal? diff2 = null;
- if (cached.Length > 1)
- {
- if (cached[cached.Length - 1].Time - cached[0].Time > TimeSpan.FromMinutes(3.5))
- {
- diff2 = cached[cached.Length - 1].Value - cached[0].Value;
- await LogPrice(message, "changemode2", diff2.Value);
- }
- }
- if (diff5min < -0.2m || (diff2.HasValue && diff2 < -0.3m))
- {
- res[TradingEvent.UptrendStart] = Constants.BlockingCoefficient;
- }
- if (diff5min > 0.2m || (diff2.HasValue && diff2 > 0.3m))
- {
- res[TradingEvent.DowntrendStart] = Constants.BlockingCoefficient;
- }
- if (diff5min > 2m)
- {
- res[TradingEvent.UptrendEnd] = Constants.BlockingCoefficient;
- }
- if (diff5min < -2m)
- {
- res[TradingEvent.DowntrendEnd] = Constants.BlockingCoefficient;
- }
- //res = MergeResultsMult(res, blocks.ToImmutableDictionary());
- return res.ToImmutableDictionary();
- }
-
- private async Task> GetWindowAverageStartData((DateTime[] timestamps, decimal[] prices) data, int smallWindow, int bigWindow,
-INewPrice message, int windowMaxSize, decimal? uptrendStartingDetectionMeanfullStep = null, decimal? uptrendEndingDetectionMeanfullStep = null)
- {
- var resultMoveAvFull = MovingAverage.CheckByWindowAverageMean2(data.timestamps, data.prices,
- windowMaxSize, smallWindow, bigWindow, uptrendStartingDetectionMeanfullStep, uptrendEndingDetectionMeanfullStep);
- if (resultMoveAvFull.bigWindowAv != 0)
- {
- await LogPrice(message, Constants.BigWindowCrossingAverageProcessor, resultMoveAvFull.bigWindowAv);
- await LogPrice(message, Constants.SmallWindowCrossingAverageProcessor, resultMoveAvFull.smallWindowAv);
- }
- var res = GetInitDict(0);
- res[TradingEvent.DowntrendEnd] = Constants.PowerLowingCoefficient;
- res[TradingEvent.UptrendEnd] = Constants.PowerLowingCoefficient;
- if ((resultMoveAvFull.events & TradingEvent.UptrendStart) == TradingEvent.UptrendStart)
- {
- res[TradingEvent.UptrendStart] = Constants.UppingCoefficient;
- //res[TradingEvent.DowntrendEnd] = Constants.UppingCoefficient;
- }
- if ((resultMoveAvFull.events & TradingEvent.UptrendEnd) == TradingEvent.UptrendEnd)
- {
- //res[TradingEvent.UptrendEnd] = Constants.UppingCoefficient;
- res[TradingEvent.DowntrendStart] = Constants.UppingCoefficient;
- }
- return res;
- }
-
- private async Task> GetPriceDiff2Mods((DateTime[] timestamps, decimal[] prices) data, int smallWindow, int bigWindow,
-INewPrice message, int windowMaxSize, decimal? uptrendStartingDetectionMeanfullStep = null, decimal? uptrendEndingDetectionMeanfullStep = null)
- {
- var res = GetInitDict(0);
-
- if (privcesDiffDiff.TryGetValue(message.Figi, out var dprice2) && privcesDiffDiffPrev.TryGetValue(message.Figi, out var dprice2_prev))
- {
- if ((dprice2 < 0 && dprice2_prev > 0) || (dprice2 > 0 && dprice2_prev < 0))
- {
- res[TradingEvent.DowntrendStart] = Constants.UppingCoefficient;
- }
- }
- return res;
- //res[TradingEvent.DowntrendEnd] = Constants.PowerLowingCoefficient;
- //res[TradingEvent.UptrendEnd] = Constants.PowerLowingCoefficient;
- //if ((resultMoveAvFull.events & TradingEvent.UptrendStart) == TradingEvent.UptrendStart)
- //{
- // res[TradingEvent.UptrendStart] = Constants.UppingCoefficient;
- // //res[TradingEvent.DowntrendEnd] = Constants.UppingCoefficient;
- //}
- //if ((resultMoveAvFull.events & TradingEvent.UptrendEnd) == TradingEvent.UptrendEnd)
- //{
- // //res[TradingEvent.UptrendEnd] = Constants.UppingCoefficient;
- // res[TradingEvent.DowntrendStart] = Constants.UppingCoefficient;
- //}
- //return res;
- }
-
-
- private async Task> GetWindowAverageStartData2((DateTime[] timestamps, decimal[] prices) data, int smallWindow, int bigWindow,
-INewPrice message, int windowMaxSize, decimal? uptrendStartingDetectionMeanfullStep = null, decimal? uptrendEndingDetectionMeanfullStep = null)
- {
- var res = GetInitDict(0);
- var resultMoveAvFull = MovingAverage.CheckByWindowAverageMean2(data.timestamps, data.prices,
- windowMaxSize, smallWindow, bigWindow, uptrendStartingDetectionMeanfullStep, uptrendEndingDetectionMeanfullStep);
- if (resultMoveAvFull.bigWindowAv != 0)
- {
- await LogPrice(message, Constants.BigWindowCrossingAverageProcessor, resultMoveAvFull.bigWindowAv);
- await LogPrice(message, Constants.SmallWindowCrossingAverageProcessor, resultMoveAvFull.smallWindowAv);
- }
-
- if (correlationsPrev.TryGetValue(message.Figi, out var oldC) && correlations.TryGetValue(message.Figi, out var c))
- {
- if ((oldC < 0 && c > 0) || (oldC > 0 && c < 0))
- {
- if (resultMoveAvFull.bigWindowAv - resultMoveAvFull.smallWindowAv > 0.5m)
- {
- res[TradingEvent.DowntrendStart] = Constants.UppingCoefficient;
- }
-
- if (resultMoveAvFull.smallWindowAv - resultMoveAvFull.bigWindowAv > 0.5m)
- {
- res[TradingEvent.UptrendStart] = Constants.UppingCoefficient;
- }
-
- }
- }
- return res;
- //res[TradingEvent.DowntrendEnd] = Constants.PowerLowingCoefficient;
- //res[TradingEvent.UptrendEnd] = Constants.PowerLowingCoefficient;
- //if ((resultMoveAvFull.events & TradingEvent.UptrendStart) == TradingEvent.UptrendStart)
- //{
- // res[TradingEvent.UptrendStart] = Constants.UppingCoefficient;
- // //res[TradingEvent.DowntrendEnd] = Constants.UppingCoefficient;
- //}
- //if ((resultMoveAvFull.events & TradingEvent.UptrendEnd) == TradingEvent.UptrendEnd)
- //{
- // //res[TradingEvent.UptrendEnd] = Constants.UppingCoefficient;
- // res[TradingEvent.DowntrendStart] = Constants.UppingCoefficient;
- //}
- //return res;
- }
-
- private async Task GetAreasRelation((DateTime[] timestamps, decimal[] prices) data, INewPrice message)
- {
- var areasRel = -1m;
- if (ShapeAreaCalculator.TryGetAreasRelation(data.timestamps, data.prices, message.Value, Constants.AreasRelationWindow, out var rel))
- {
- await _tradeDataProvider.AddDataTo1MinuteWindowCache(message.Figi, Constants._1minCacheKey, new Contracts.Declisions.Dtos.CachedValue()
- {
- Time = message.Time,
- Value = (decimal)rel
- });
- var areas = await _tradeDataProvider.GetDataFrom1MinuteWindowCache(message.Figi, Constants._1minCacheKey);
-
- areasRel = (decimal)areas.Sum(a => a.Value) / areas.Length;
- await LogPrice(message, Constants.AreasRelationProcessor, areasRel);
- return areasRel > 0 ? areasRel : null;
- }
- return null;
- }
-
- private async Task CheckHarmonicPosition(INewPrice message)
- {
- var data2 = await GetData(message);
- var position = await CheckHarmonicPosition(data2, message);
- return position;
- }
-
private async Task ClosePositions(Asset[] assets, INewPrice message, bool withProfitOnly = true)
{
var loggedDeclisions = 0;
@@ -1031,7 +435,7 @@ INewPrice message, int windowMaxSize, decimal? uptrendStartingDetectionMeanfullS
var sign = positionType == PositionType.Long ? 1 : 1;
foreach (var acc in accounts)
{
- if (IsOperationAllowed(acc, message.Value, 1, _accountCashPartFutures, _accountCashPart))
+ if (TraderUtils.IsOperationAllowed(acc, message.Value, 1, _exchangeConfig.AccountCashPartFutures, _exchangeConfig.AccountCashPart))
{
await acc.OpenPosition(message.Figi, positionType, stopLossShift, takeProfitShift, count);
await _dataBus.Broadcast(new MessageForAdmin()
@@ -1052,55 +456,14 @@ INewPrice message, int windowMaxSize, decimal? uptrendStartingDetectionMeanfullS
}
}
- private async Task ProcessNewPriceIMOEXF3((DateTime[] timestamps, decimal[] prices) data,
- ExchangeState state,
- INewPrice message, int windowMaxSize, ImmutableDictionary changeModeData)
+ private async Task ExecuteDeclisions(INewPrice message, ImmutableDictionary result)
{
- if (data.timestamps.Length <= 4)
- {
- return;
- }
-
- var steps = await GetSteps(message);
- var windows = await GetWindowsSizes(message);
- //var resTask1 = GetWindowAverageStartData(data, 30, 180, message, windowMaxSize, -2m, 2m,3);
- var resTask1 = GetWindowAverageStartData2(data, (int)windows.smallWindow, (int)windows.bigWindow, message, windowMaxSize, steps.downtrendEndStep, steps.uptrendEndStep);
-
- var corrModsTask = GetCorrelationsMods(message);
- ////var resTask3 = GetWindowAverageStartData(data, 30, 180, message, windowMaxSize, 0, 0,0.7m);
- //var getFFTModsTask = GetFFTMods(message);
- //var getLocalTrendsModsTask = GetLocalTrendsMods(data, message);
- //var getSellsDiffsModsTask = GetSellsDiffsMods(message);
- //var getTradingModeModsTask = GetTradingModeMods(message);
- var getSpeedResultantModsTask = GetSpeedResultantMods(message);
-
- await Task.WhenAll(resTask1, getSpeedResultantModsTask);
- //var assetType = _tradeDataProvider.GetAssetTypeByFigi(message.Figi);
- //if (resTask1.Result[TradingEvent.UptrendStart] >= 1)
- //{
-
- //}
-
- var result = resTask1.Result;
-
- //result = MergeResults(result, resTask2.Result.ToImmutableDictionary());
- //result = MergeResults(result, resTask3.Result.ToImmutableDictionary());
- //result = MergeResultsMax(result, changeModeData);
- //result = MergeResultsMult(result, corrModsTask.Result);
- // result = MergeResultsMax(result, getLocalTrendsModsTask.Result);
- //result = MergeResultsMult(result, getFFTModsTask.Result);
- //result = MergeResultsMult(result, getSellsDiffsModsTask.Result);
- //result = MergeResultsMult(result, getTradingModeModsTask.Result);
- //result = MergeResultsMult(result, getSpeedResultantModsTask.Result);
-
-
-
+ var state = ExchangeScheduler.GetCurrentState();
if (result[TradingEvent.UptrendStart] >= Constants.UppingCoefficient
&& !LongOpeningStops.ContainsKey(message.Figi)
&& state == ExchangeState.Open
)
{
- LastTradingEvents[message.Figi] = TradingEvent.UptrendStart;
var stops = GetStops(message, PositionType.Long);
if (!message.IsHistoricalData && BotModeSwitcher.CanPurchase())
{
@@ -1121,7 +484,6 @@ INewPrice message, int windowMaxSize, decimal? uptrendStartingDetectionMeanfullS
&& state == ExchangeState.Open
)
{
- LastTradingEvents[message.Figi] = TradingEvent.DowntrendStart;
var stops = GetStops(message, PositionType.Short);
if (!message.IsHistoricalData && BotModeSwitcher.CanPurchase())
{
@@ -1260,11 +622,11 @@ INewPrice message, int windowMaxSize, decimal? uptrendStartingDetectionMeanfullS
{
if (assetType == AssetType.Common)
{
- return _shareComission;
+ return _exchangeConfig.ShareComission;
}
else if (assetType == AssetType.Futures)
{
- return _futureComission;
+ return _exchangeConfig.FutureComission;
}
else
{
@@ -1275,53 +637,14 @@ INewPrice message, int windowMaxSize, decimal? uptrendStartingDetectionMeanfullS
private decimal GetLeverage(string figi, bool isShort)
{
var res = 1m;
- if (Leverages.TryGetValue(figi, out var leverage))
+ var leverage = _exchangeConfig.InstrumentsSettings.FirstOrDefault(l => l.Figi == figi);
+ if (leverage != null)
{
res = isShort ? leverage.ShortLeverage : leverage.LongLeverage;
}
return res;
}
- private async ValueTask CalcTradingMode(INewPrice message)
- {
- var res = TradingMode.None;
- var largeData = await _tradeDataProvider.GetData(message.Figi, TimeSpan.FromMinutes(45));
- var smallData = await _tradeDataProvider.GetData(message.Figi, TimeSpan.FromMinutes(10));
-
- if (largeData.isFullIntervalExists && smallData.isFullIntervalExists)
- {
- if (LocalTrends.TryCalcTrendDiff(largeData.timestamps, largeData.prices, out var largeDataRes)
- && LocalTrends.TryCalcTrendDiff(smallData.timestamps, smallData.prices, out var smallDataRes))
- {
- if (largeDataRes > 0 && largeDataRes <= 4 && System.Math.Abs(smallDataRes) < 3)
- {
- res = TradingMode.Stable;
- }
- if (largeDataRes < 0 && largeDataRes >= -5 && smallDataRes < 1)
- {
- res = TradingMode.SlowDropping;
- }
- if ((largeDataRes > 5 && smallDataRes > 0))
- {
- res = TradingMode.Growing;
- }
- if ((largeDataRes < -5 && smallDataRes < 0))
- {
- res = TradingMode.Dropping;
- }
- if (smallDataRes > 7)
- {
- res = TradingMode.Growing;
- }
- if (smallDataRes < -7)
- {
- res = TradingMode.Dropping;
- }
- }
- }
- return res;
- }
-
private async ValueTask CalcTradingMode2(INewPrice message)
{
var res = TradingMode.None;
@@ -1356,38 +679,6 @@ INewPrice message, int windowMaxSize, decimal? uptrendStartingDetectionMeanfullS
return res;
}
- private async Task<(decimal? downtrendEndStep, decimal? uptrendEndStep)> GetSteps(INewPrice message)
- {
- var mode = TradingModes[message.Figi];
- switch (mode)
- {
- case TradingMode.Stable:
- {
- return (-0.5m, 0.5m);
- }
- case TradingMode.Dropping:
- {
- return (-1.5m, 0.5m); ;
- }
- case TradingMode.SlowDropping:
- {
- return (-1m, 0.5m);
- }
- case TradingMode.SlowGrowing:
- {
- return (-0.5m, 1m);
- }
- case TradingMode.Growing:
- {
- return (-0.5m, 1.5m);
- }
- default:
- {
- return (-0.5m, 0.5m);
- }
- }
- }
-
private (decimal stopLoss, decimal takeProfit) GetStops(INewPrice message, PositionType type)
{
var mode = TradingModes[message.Figi];
@@ -1442,161 +733,9 @@ INewPrice message, int windowMaxSize, decimal? uptrendStartingDetectionMeanfullS
return (stopLossShift, takeProfitShift);
}
- private async Task> GetFFTMods(INewPrice message)
- {
- var res = GetInitDict(1);
- var position = await CheckHarmonicPosition(message);
-
- if (position == ValueAmplitudePosition.LowerThenMedianaGrowing)
- {
- //res[TradingEvent.UptrendStart] = Constants.UppingCoefficient;
- res[TradingEvent.DowntrendEnd] = Constants.UppingCoefficient;
- //res[TradingEvent.UptrendEnd] = Constants.LowingCoefficient;
- res[TradingEvent.DowntrendStart] = Constants.LowingCoefficient;
- }
- if (position == ValueAmplitudePosition.UpperThen30Decil)
- {
- res[TradingEvent.UptrendStart] = Constants.LowingCoefficient;
- //res[TradingEvent.DowntrendEnd] = Constants.LowingCoefficient;
- //res[TradingEvent.UptrendEnd] = Constants.UppingCoefficient;
- res[TradingEvent.DowntrendEnd] = Constants.UppingCoefficient;
- }
- return res.ToImmutableDictionary();
- }
-
- private async Task> GetAreasMods((DateTime[] timestamps, decimal[] prices) data, INewPrice message)
- {
- var res = GetInitDict(1);
- var areas = await GetAreasRelation(data, message);
- if (areas.HasValue && areas.Value > 0.2m && areas.Value <= 0.8m)
- {
- //res[TradingEvent.UptrendStart] = Constants.PowerLowingCoefficient;
- }
- if (areas.HasValue && areas.Value > 0.8m)
- {
- //res[TradingEvent.DowntrendStart] = Constants.UppingCoefficient;
- //res[TradingEvent.DowntrendEnd] = Constants.UppingCoefficient;
- }
- return res.ToImmutableDictionary();
- }
-
- private Task> GetLocalTrendsMods((DateTime[] timestamps, decimal[] prices) data, INewPrice message)
- {
- var res = GetInitDict(0);
- if (LocalTrends.TryGetLocalTrends(data.timestamps, data.prices, TimeSpan.FromSeconds(15), TimeSpan.FromSeconds(15), 0.5, out var localTrends))
- {
- if ((localTrends & TradingEvent.UptrendEnd) == TradingEvent.UptrendEnd)
- {
- res[TradingEvent.UptrendEnd] = Constants.PowerUppingCoefficient;
- }
- if ((localTrends & TradingEvent.DowntrendEnd) == TradingEvent.DowntrendEnd)
- {
- res[TradingEvent.DowntrendEnd] = Constants.PowerUppingCoefficient;
- }
- }
- return Task.FromResult(res.ToImmutableDictionary());
- }
-
-
- private async Task> GetCorrelationsMods(INewPrice message)
- {
- var res = GetInitDict(1);
-
- return res.ToImmutableDictionary();
- if (PirsonZeroCrossings.TryGetValue(message.Figi, out var pir))
- {
- if (PricesZeroCrossingsUp.TryGetValue(message.Figi, out var prU))
- {
- var dt1 = message.Time - prU;
- var dt2 = message.Time - pir;
-
- if (dt1 < TimeSpan.FromMinutes(0.5) && dt2 < TimeSpan.FromMinutes(0.5))
- {
- //res[TradingEvent.DowntrendStart] = Constants.UppingCoefficient;
- res[TradingEvent.UptrendStart] = Constants.UppingCoefficient;
- }
- }
- if (PricesZeroCrossingsDown.TryGetValue(message.Figi, out var prD))
- {
- var dt1 = message.Time - prD;
- var dt2 = message.Time - pir;
-
- if (dt1 < TimeSpan.FromMinutes(0.5) && dt2 < TimeSpan.FromMinutes(0.5))
- {
- res[TradingEvent.DowntrendStart] = Constants.UppingCoefficient;
- //res[TradingEvent.UptrendStart] = Constants.UppingCoefficient;
- }
- }
- }
- return res.ToImmutableDictionary();
- }
-
- private async Task> GetSellsDiffsMods(INewPrice message)
- {
- var res = GetInitDict(1);
- var sberSells5min = await _tradeDataProvider.GetDataFrom5MinuteWindowCache("BBG004730N88", Constants._5minSellCacheKey);
- var sberBuys5min = await _tradeDataProvider.GetDataFrom5MinuteWindowCache("BBG004730N88", Constants._5minBuyCacheKey);
-
- var sberSells1min = await _tradeDataProvider.GetDataFrom1MinuteWindowCache("BBG004730N88", Constants._1minSellCacheKey);
- var sberBuys1min = await _tradeDataProvider.GetDataFrom1MinuteWindowCache("BBG004730N88", Constants._1minBuyCacheKey);
-
- var sells5min = sberSells5min.Sum(s => s.Value);
- var buys5min = sberBuys5min.Sum(s => s.Value);
- var sells1min = sberSells1min.Sum(s => s.Value);
- var buys1min = sberBuys1min.Sum(s => s.Value);
-
- var su = sells5min + buys5min;
- var uptrendEndMode = 1m;
- var downtrendEndMode = 1m;
- var downstartMode = 1m;
- var uptrendStartMode = 1m;
-
-
- if (su != 0)
- {
- var trades_rel = (sells5min / su - 0.5m) * 2;
- var bys_rel = buys1min / su;
- var sells_rel = sells1min / su;
- await LogPrice(message, "trades_rel", trades_rel);
- await LogPrice(message, "bys_rel", bys_rel);
- await LogPrice(message, "sells_rel", sells_rel);
-
- if (trades_rel > 0.7m)
- {
- //uptrendStartMode *= Constants.LowingCoefficient;
- }
-
- if (System.Math.Abs(bys_rel) > 0.6m || System.Math.Abs(sells_rel) > 0.6m)
- {
- uptrendStartMode *= Constants.PowerUppingCoefficient;
- downstartMode *= Constants.PowerUppingCoefficient;
- uptrendEndMode *= Constants.BlockingCoefficient;
- downtrendEndMode *= Constants.BlockingCoefficient;
- }
- else if (System.Math.Abs(bys_rel) > 0.3m || System.Math.Abs(sells_rel) > 0.3m)
- {
- uptrendStartMode *= Constants.UppingCoefficient;
- downstartMode *= Constants.UppingCoefficient;
- uptrendEndMode *= Constants.LowingCoefficient;
- downtrendEndMode *= Constants.LowingCoefficient;
- }
- //else if (System.Math.Abs(bys_rel) <= 0.2m && System.Math.Abs(sells_rel) <= 0.2m)
- //{
- // uptrendEndMode *= Constants.UppingCoefficient;
- // downtrendEndMode *= Constants.UppingCoefficient;
- //}
-
- res[TradingEvent.UptrendStart] = uptrendStartMode;
- res[TradingEvent.UptrendEnd] = uptrendEndMode;
- res[TradingEvent.DowntrendEnd] = downtrendEndMode;
- res[TradingEvent.DowntrendStart] = downstartMode;
- }
- return res.ToImmutableDictionary();
- }
-
private Task> GetTradingModeMods(INewPrice message)
{
- var res = GetInitDict(1);
+ var res = TraderUtils.GetInitDict(1);
var mode = TradingModes[message.Figi];
if (mode == TradingMode.None)
{
@@ -1636,53 +775,5 @@ INewPrice message, int windowMaxSize, decimal? uptrendStartingDetectionMeanfullS
return Task.FromResult(res.ToImmutableDictionary());
}
- internal static bool IsOperationAllowed(IManagedAccount account, decimal boutPrice, decimal count,
- decimal accountCashPartFutures, decimal accountCashPart)
- {
- if (!BotModeSwitcher.CanPurchase()) return false;
-
- var balance = account.Balance;
- var total = account.Total;
-
- var futures = account.Assets.Values.FirstOrDefault(v => v.Type == AssetType.Futures);
- if (futures != null)
- {
- if ((balance - boutPrice * count) / total < accountCashPartFutures) return false;
- }
- else
- {
- if ((balance - boutPrice * count) / total < accountCashPart) return false;
- }
-
- return true;
- }
-
- private static Dictionary GetInitDict(decimal initValue)
- {
- var values = System.Enum.GetValues();
- return values.ToDictionary(v => v, v => initValue);
- }
-
- private static Dictionary MergeResultsMult(Dictionary res, ImmutableDictionary data)
- {
- foreach (var k in res.Keys)
- {
- var valRes = res[k];
- var valData = data[k];
- res[k] = valRes * valData;
- }
- return res;
- }
-
- private static Dictionary MergeResultsMax(Dictionary res, ImmutableDictionary data)
- {
- foreach (var k in res.Keys)
- {
- var valRes = res[k];
- var valData = data[k];
- res[k] = System.Math.Max(valRes, valData);
- }
- return res;
- }
}
}
diff --git a/KLHZ.Trader.Core/Exchange/Services/TraderDataProvider.cs b/KLHZ.Trader.Core/Exchange/Services/TraderDataProvider.cs
index eea3fa3..cdd5658 100644
--- a/KLHZ.Trader.Core/Exchange/Services/TraderDataProvider.cs
+++ b/KLHZ.Trader.Core/Exchange/Services/TraderDataProvider.cs
@@ -257,7 +257,7 @@ namespace KLHZ.Trader.Core.Exchange.Services
{
if (ShapeAreaCalculator.TryGetAreasRelation(cachedData.timestamps, cachedData.prices, price.Value, Constants.AreasRelationWindow, out var rel))
{
- await AddDataTo1MinuteWindowCache(price.Figi, Constants._1minCacheKey, new CachedValue() { Time = price.Time, Value = (decimal)rel });
+ await AddDataTo1MinuteWindowCache(price.Figi, Constants._1minCacheKey, new CachedValue() { Time = price.Time, Count = (decimal)rel });
}
}
}
diff --git a/KLHZ.Trader.Core/Exchange/Utils/TraderUtils.cs b/KLHZ.Trader.Core/Exchange/Utils/TraderUtils.cs
new file mode 100644
index 0000000..4c4920c
--- /dev/null
+++ b/KLHZ.Trader.Core/Exchange/Utils/TraderUtils.cs
@@ -0,0 +1,93 @@
+using KLHZ.Trader.Core.Common;
+using KLHZ.Trader.Core.Contracts.Declisions.Dtos.Enums;
+using KLHZ.Trader.Core.Contracts.Messaging.Dtos.Interfaces;
+using KLHZ.Trader.Core.DataLayer.Entities.Prices;
+using KLHZ.Trader.Core.Exchange.Interfaces;
+using KLHZ.Trader.Core.Exchange.Models.AssetsAccounting;
+using System.Collections.Immutable;
+
+namespace KLHZ.Trader.Core.Exchange.Utils
+{
+ internal static class TraderUtils
+ {
+ internal static Dictionary MergeResultsMult(Dictionary res, ImmutableDictionary data)
+ {
+ foreach (var k in res.Keys)
+ {
+ var valRes = res[k];
+ var valData = data[k];
+ res[k] = valRes * valData;
+ }
+ return res;
+ }
+
+ internal static Dictionary MergeResultsMax(Dictionary res, ImmutableDictionary data)
+ {
+ foreach (var k in res.Keys)
+ {
+ var valRes = res[k];
+ var valData = data[k];
+ res[k] = System.Math.Max(valRes, valData);
+ }
+ return res;
+ }
+ internal static Dictionary GetInitDict(decimal initValue)
+ {
+ var values = System.Enum.GetValues();
+ return values.ToDictionary(v => v, v => initValue);
+ }
+
+ internal static bool IsOperationAllowed(IManagedAccount account, decimal boutPrice, decimal count,
+ decimal accountCashPartFutures, decimal accountCashPart)
+ {
+ if (!BotModeSwitcher.CanPurchase()) return false;
+
+ var balance = account.Balance;
+ var total = account.Total;
+
+ var futures = account.Assets.Values.FirstOrDefault(v => v.Type == AssetType.Futures);
+ if (futures != null)
+ {
+ if ((balance - boutPrice * count) / total < accountCashPartFutures) return false;
+ }
+ else
+ {
+ if ((balance - boutPrice * count) / total < accountCashPart) return false;
+ }
+
+ return true;
+ }
+
+ internal static INewPrice FilterHighFreqValues(INewPrice message, Dictionary> pricesCache1)
+ {
+ if (!pricesCache1.TryGetValue(message.Figi, out var list))
+ {
+ list = new List();
+ pricesCache1[message.Figi] = list;
+ }
+ list.Add(message);
+
+ if ((list.Last().Time - list.First().Time).TotalSeconds < 0.5)
+ {
+ list.Add(message);
+ return message;
+ }
+ else
+ {
+ message = new PriceChange()
+ {
+ Figi = message.Figi,
+ Ticker = message.Ticker,
+ Count = list.Sum(l => l.Count),
+ Direction = message.Direction,
+ IsHistoricalData = message.IsHistoricalData,
+ Time = message.Time,
+ Value = list.Sum(l => l.Value) / list.Count
+ };
+ list.Clear();
+ return message;
+ }
+ }
+
+ }
+}