Чистка кода

dev
vlad zverzhkhovskiy 2025-10-07 13:05:38 +03:00
parent 00de5bee2e
commit 64c702ebf1
17 changed files with 135 additions and 732 deletions

View File

@ -1,9 +1,15 @@
namespace KLHZ.Trader.Core.Contracts.Declisions.Dtos
{
public class CachedValue
public class CachedValue //: ICachedValue
{
public DateTime Time { get; init; }
public decimal Count { get; init; }
public long Count { get; init; }
public decimal Price { get; init; }
public decimal Value { get; init; }
public decimal Value2 { get; init; }
//public bool IsHistoricalData { get; init; }
//public required string Figi { get; init; } = string.Empty;
//public required string Ticker { get; init; } = string.Empty;
//public int Direction { get; init; }
}
}

View File

@ -0,0 +1,10 @@
using KLHZ.Trader.Core.Contracts.Messaging.Dtos.Interfaces;
namespace KLHZ.Trader.Core.Contracts.Declisions.Interfaces
{
internal interface ICachedValue : INewPrice
{
public decimal Value { get; }
public decimal Value2 { get; }
}
}

View File

@ -2,12 +2,12 @@
{
public interface INewPrice
{
public bool IsHistoricalData { get; set; }
public decimal Value { get; set; }
public string Figi { get; set; }
public string Ticker { get; set; }
public DateTime Time { get; set; }
public long Count { get; set; }
public int Direction { get; set; }
public bool IsHistoricalData { get; }
public decimal Price { get; }
public string Figi { get; }
public string Ticker { get; }
public DateTime Time { get; }
public long Count { get; }
public int Direction { get; }
}
}

View File

@ -4,7 +4,7 @@ namespace KLHZ.Trader.Core.Contracts.Messaging.Dtos
{
public class NewPriceMessage : INewPrice
{
public decimal Value { get; set; }
public decimal Price { get; set; }
public required string Figi { get; set; }
public required string Ticker { get; set; }
public DateTime Time { get; set; }

View File

@ -111,7 +111,7 @@ namespace KLHZ.Trader.Core.Math.Declisions.Services.Cache
lock (_locker)
{
_pointer++;
Prices[_pointer] = priceChange.Value;
Prices[_pointer] = priceChange.Price;
Timestamps[_pointer] = priceChange.Time;
if (_length < CacheMaxLength)
{

View File

@ -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.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));
var sum1 = (double)values.Sum(d => (d.Value2 - tradevolume_diffMean) * (d.Value - dprice_diffMean));
var sum2 = values.Sum(d => (d.Value2 - tradevolume_diffMean) * (d.Value2 - tradevolume_diffMean));
var sum3 = values.Sum(d => (d.Value - dprice_diffMean) * (d.Value - dprice_diffMean));
if (sum2 != 0 && sum3 != 0)
{
result = (decimal)(sum1 / System.Math.Sqrt((double)(sum2 * sum3)));

View File

@ -20,7 +20,7 @@ namespace KLHZ.Trader.Core.Tests
Ticker = figi + "_ticker",
Id = i,
Time = startDt,
Value = (decimal)(i + 0.5)
Price = (decimal)(i + 0.5)
};
}
}
@ -53,7 +53,7 @@ namespace KLHZ.Trader.Core.Tests
Assert.That(data.timestamps.Length == count);
for (var i = 0; i < count; i++)
{
Assert.That((float)hist[i].Value, Is.EqualTo(data.prices[i]));
Assert.That((float)hist[i].Price, Is.EqualTo(data.prices[i]));
Assert.That(hist[i].Time, Is.EqualTo(data.timestamps[i]));
}
}
@ -72,7 +72,7 @@ namespace KLHZ.Trader.Core.Tests
for (var i = 0; i < count; i++)
{
Assert.That((float)hist[i].Value, Is.EqualTo(data.prices[i]));
Assert.That((float)hist[i].Price, Is.EqualTo(data.prices[i]));
Assert.That(hist[i].Time, Is.EqualTo(data.timestamps[i]));
}
}
@ -91,7 +91,7 @@ namespace KLHZ.Trader.Core.Tests
for (var i = 0; i < count; i++)
{
Assert.That((float)hist[i].Value, Is.EqualTo(data.prices[i]));
Assert.That((float)hist[i].Price, Is.EqualTo(data.prices[i]));
Assert.That(hist[i].Time, Is.EqualTo(data.timestamps[i]));
}
}
@ -114,7 +114,7 @@ namespace KLHZ.Trader.Core.Tests
var k = i + shift;
if (k < hist.Length)
{
Assert.That((float)hist[k].Value, Is.EqualTo(data.prices[i]));
Assert.That((float)hist[k].Price, Is.EqualTo(data.prices[i]));
Assert.That(hist[k].Time, Is.EqualTo(data.timestamps[i]));
}
}
@ -138,7 +138,7 @@ namespace KLHZ.Trader.Core.Tests
var k = i + shift;
if (k < hist.Length)
{
Assert.That((float)hist[k].Value, Is.EqualTo(data.prices[i]));
Assert.That((float)hist[k].Price, Is.EqualTo(data.prices[i]));
Assert.That(hist[k].Time, Is.EqualTo(data.timestamps[i]));
}
}
@ -162,7 +162,7 @@ namespace KLHZ.Trader.Core.Tests
var k = i + shift;
if (k < hist.Length)
{
Assert.That((float)hist[k].Value, Is.EqualTo(data.prices[i]));
Assert.That((float)hist[k].Price, Is.EqualTo(data.prices[i]));
Assert.That(hist[k].Time, Is.EqualTo(data.timestamps[i]));
}
}
@ -183,24 +183,24 @@ namespace KLHZ.Trader.Core.Tests
for (var i = 0; i < count; i++)
{
Assert.That((float)hist[i].Value, Is.EqualTo(data.prices[i]));
Assert.That((float)hist[i].Price, Is.EqualTo(data.prices[i]));
Assert.That(hist[i].Time, Is.EqualTo(data.timestamps[i]));
}
var newData1 = new PriceChange() { Figi = figi, Ticker = figi, Value = 100500, Time = DateTime.UtcNow };
var newData1 = new PriceChange() { Figi = figi, Ticker = figi, Price = 100500, Time = DateTime.UtcNow };
cacheUnit.AddData(newData1);
var data2 = cacheUnit.GetData().Result;
Assert.IsTrue(data2.prices[data2.prices.Length - 1] == newData1.Value);
Assert.IsTrue(data2.prices[data2.prices.Length - 1] == newData1.Price);
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, Price = 100501, Time = DateTime.UtcNow };
cacheUnit.AddData(newData2);
var data3 = cacheUnit.GetData().Result;
Assert.IsTrue(data3.prices[data3.prices.Length - 1] == newData2.Value);
Assert.IsTrue(data3.prices[data3.prices.Length - 1] == newData2.Price);
Assert.IsTrue(data3.timestamps[data3.timestamps.Length - 1] == newData2.Time);
}
@ -210,7 +210,7 @@ namespace KLHZ.Trader.Core.Tests
var cacheUnit = new PriceHistoryCacheUnit2("");
for (int i = 0; i < 5 * PriceHistoryCacheUnit2.CacheMaxLength; i++)
{
cacheUnit.AddData(new PriceChange() { Figi = "", Ticker = "", Value = i, Time = DateTime.UtcNow });
cacheUnit.AddData(new PriceChange() { Figi = "", Ticker = "", Price = i, Time = DateTime.UtcNow });
if (i >= PriceHistoryCacheUnit2.CacheMaxLength)
{
var data = cacheUnit.GetData().Result;
@ -237,11 +237,11 @@ namespace KLHZ.Trader.Core.Tests
Assert.That(data.prices.Length == length);
Assert.That(data.timestamps.Length == length);
Assert.That(data.prices.Last() == hist.Last().Value);
Assert.That(data.prices.Last() == hist.Last().Price);
Assert.That(data.timestamps.Last() == hist.Last().Time);
for (var i = 1; i <= length; i++)
{
Assert.That(hist[hist.Length - i].Value, Is.EqualTo(data.prices[data.prices.Length - i]));
Assert.That(hist[hist.Length - i].Price, Is.EqualTo(data.prices[data.prices.Length - i]));
Assert.That(hist[hist.Length - i].Time, Is.EqualTo(data.timestamps[data.prices.Length - i]));
}
}
@ -267,7 +267,7 @@ namespace KLHZ.Trader.Core.Tests
Assert.That(data.prices.Length == length);
Assert.That(data.timestamps.Length == length);
Assert.That(data.prices.Last() == hist.Last().Value);
Assert.That(data.prices.Last() == hist.Last().Price);
Assert.That(data.timestamps.Last() == hist.Last().Time);
}

View File

@ -13,7 +13,7 @@ namespace KLHZ.Trader.Core.DataLayer.Entities.Prices
public DateTime Time { get; set; }
[Column("value")]
public decimal Value { get; set; }
public decimal Price { get; set; }
[Column("figi")]
public required string Figi { get; set; }

View File

@ -13,7 +13,7 @@ namespace KLHZ.Trader.Core.DataLayer.Entities.Prices
public DateTime Time { get; set; }
[Column("value")]
public decimal Value { get; set; }
public decimal Price { get; set; }
[Column("figi")]
public required string Figi { get; set; }

View File

@ -3,12 +3,10 @@
public class ExchangeConfig
{
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; } = [];

View File

@ -149,7 +149,7 @@ namespace KLHZ.Trader.Core.Exchange.Services
Figi = response.Trade.Figi,
Ticker = _tradeDataProvider.GetTickerByFigi(response.Trade.Figi),
Time = response.Trade.Time.ToDateTime().ToUniversalTime(),
Value = response.Trade.Price,
Price = response.Trade.Price,
IsHistoricalData = false,
Direction = (int)response.Trade.Direction,
Count = response.Trade.Quantity,

View File

@ -39,11 +39,6 @@ namespace KLHZ.Trader.Core.Exchange.Services
private readonly ConcurrentDictionary<string, decimal> DPirsonValues = new();
private readonly ConcurrentDictionary<string, DateTime> LongOpeningStops = new();
private readonly ConcurrentDictionary<string, DateTime> ShortOpeningStops = new();
private readonly ConcurrentDictionary<string, DateTime> LongClosingStops = new();
private readonly ConcurrentDictionary<string, DateTime> ShortClosingStops = new();
private readonly Channel<INewPrice> _pricesChannel = Channel.CreateUnbounded<INewPrice>();
private readonly Channel<ITradeCommand> _commands = Channel.CreateUnbounded<ITradeCommand>();
private readonly Channel<IOrderbook> _orderbooks = Channel.CreateUnbounded<IOrderbook>();
@ -87,7 +82,7 @@ namespace KLHZ.Trader.Core.Exchange.Services
if (command.CommandType == Contracts.Messaging.Dtos.Enums.TradeCommandType.OpenLong
|| command.CommandType == Contracts.Messaging.Dtos.Enums.TradeCommandType.OpenShort)
{
var fakeMessage = new NewPriceMessage() { Figi = command.Figi, Ticker = "", Count = command.Count, Direction = 1, IsHistoricalData = false, Time = DateTime.UtcNow, Value = command.RecomendPrice ?? 0m };
var fakeMessage = new NewPriceMessage() { Figi = command.Figi, Ticker = "", Count = command.Count, Direction = 1, IsHistoricalData = false, Time = DateTime.UtcNow, Price = command.RecomendPrice ?? 0m };
var positionType = command.CommandType == TradeCommandType.OpenLong ? PositionType.Long : PositionType.Short;
var stops = GetStops(fakeMessage, positionType);
var accounts = _portfolioWrapper.Accounts
@ -99,7 +94,7 @@ namespace KLHZ.Trader.Core.Exchange.Services
}
else
{
var fakeMessage = new NewPriceMessage() { Figi = command.Figi, Ticker = "", Count = command.Count, Direction = 1, IsHistoricalData = false, Time = DateTime.UtcNow, Value = command.RecomendPrice ?? 0m };
var fakeMessage = new NewPriceMessage() { Figi = command.Figi, Ticker = "", Count = command.Count, Direction = 1, IsHistoricalData = false, Time = DateTime.UtcNow, Price = command.RecomendPrice ?? 0m };
var assetsForClose = _portfolioWrapper.Accounts
.SelectMany(a => a.Value.Assets.Values)
.Where(a => a.Figi == fakeMessage.Figi)
@ -109,7 +104,7 @@ namespace KLHZ.Trader.Core.Exchange.Services
}
catch (Exception ex)
{
_logger.LogError(ex, "Ошибка при выполнении команды.");
}
}
}
@ -123,7 +118,6 @@ namespace KLHZ.Trader.Core.Exchange.Services
}
}
private async Task ProcessPrices()
{
var pricesCache1 = new Dictionary<string, List<INewPrice>>();
@ -150,27 +144,27 @@ namespace KLHZ.Trader.Core.Exchange.Services
{
Time = message.Time,
Count = message.Count,
Price = message.Value,
Price = message.Price,
});
await _tradeDataProvider.AddDataTo5MinuteWindowCache(message.Figi, Constants._5minBuyCacheKey, new Contracts.Declisions.Dtos.CachedValue()
{
Time = message.Time,
Count = (decimal)message.Count,
Price = message.Value,
Count = message.Count,
Price = message.Price,
});
await _tradeDataProvider.AddDataTo15MinuteWindowCache(message.Figi, Constants._15minBuyCacheKey, new Contracts.Declisions.Dtos.CachedValue()
{
Time = message.Time,
Count = (decimal)message.Count,
Price = message.Value,
Count = message.Count,
Price = message.Price,
});
await _tradeDataProvider.AddDataTo1MinuteWindowCache(message.Figi, Constants._1minBuyCacheKey, new Contracts.Declisions.Dtos.CachedValue()
{
Time = message.Time,
Count = (decimal)message.Count,
Price = message.Value,
Count = message.Count,
Price = message.Price,
});
}
if (message.Direction == 2)
@ -178,201 +172,101 @@ namespace KLHZ.Trader.Core.Exchange.Services
await _tradeDataProvider.AddDataTo5MinuteWindowCache(message.Figi, Constants._5minSellCacheKey, new Contracts.Declisions.Dtos.CachedValue()
{
Time = message.Time,
Count = (decimal)message.Count,
Price = message.Value,
Count = message.Count,
Price = message.Price,
});
await _tradeDataProvider.AddDataTo15MinuteWindowCache(message.Figi, Constants._15minSellCacheKey, new Contracts.Declisions.Dtos.CachedValue()
{
Time = message.Time,
Count = (decimal)message.Count,
Price = message.Value,
Count = message.Count,
Price = message.Price,
});
await _tradeDataProvider.AddDataTo1MinuteWindowCache(message.Figi, Constants._1minSellCacheKey, new Contracts.Declisions.Dtos.CachedValue()
{
Time = message.Time,
Count = (decimal)message.Count,
Price = message.Value,
Count = message.Count,
Price = message.Price,
});
await _tradeDataProvider.AddDataTo20SecondsWindowCache(message.Figi, "2", new Contracts.Declisions.Dtos.CachedValue()
{
Time = message.Time,
Count = message.Count,
Price = message.Value,
Price = message.Price,
});
}
}
#endregion
if (_exchangeConfig.TradingInstrumentsFigis.Contains(message.Figi) && (message.Figi == "FUTIMOEXF000" || message.Figi == "BBG004730N88") && message.Direction == 1)
if (_exchangeConfig.TradingInstrumentsFigis.Contains(message.Figi) && message.Direction == 1)
{
var smallWindow = TimeSpan.FromSeconds(120);
var bigWindow = TimeSpan.FromSeconds(240);
var meanWindow = TimeSpan.FromSeconds(240);
var currentTime = message.IsHistoricalData ? message.Time : DateTime.UtcNow;
try
{
var buys = await _tradeDataProvider.GetDataFrom15MinuteWindowCache(message.Figi, Constants._15minBuyCacheKey);
var sells = await _tradeDataProvider.GetDataFrom15MinuteWindowCache(message.Figi, Constants._15minSellCacheKey);
var trades = buys.ToList();
trades.AddRange(sells);
var trades2 = trades.OrderBy(t => t.Time).ToArray();
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,
Count = tradesDiff,
Price = pricesDiff,
});
var diffs = await _tradeDataProvider.GetDataFrom15MinuteWindowCache(message.Figi, "5min_diff");
if (diffs.TryCalcTimeWindowsDiff(bigWindow, smallWindow, (c) => c.Price, true, out var resdp)
&& diffs.TryCalcTimeWindowsDiff(bigWindow, smallWindow, (c) => c.Count, true, out var resv))
var buys = await _tradeDataProvider.GetDataFrom15MinuteWindowCache(message.Figi, Constants._15minBuyCacheKey);
var sells = await _tradeDataProvider.GetDataFrom15MinuteWindowCache(message.Figi, Constants._15minSellCacheKey);
var trades = buys.ToList();
trades.AddRange(sells);
var trades2 = trades.OrderBy(t => t.Time).ToArray();
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,
Value2 = tradesDiff,
Value = pricesDiff,
});
var diffs = await _tradeDataProvider.GetDataFrom15MinuteWindowCache(message.Figi, "5min_diff");
if (diffs.TryCalcTimeWindowsDiff(bigWindow, smallWindow, (c) => c.Value, true, out var resdp)
&& diffs.TryCalcTimeWindowsDiff(bigWindow, smallWindow, (c) => c.Value2, true, out var resv))
{
await LogPrice(message, "privcesDiffDiff", (decimal)resdp);
await LogPrice(message, "tradevolume_diff_diff", (decimal)resv);
if (diffs.TryCalcPirsonCorrelation(meanWindow, out var pirson))
{
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()
await LogPrice(message, "diffs_pirson", (decimal)pirson);
await _tradeDataProvider.AddDataTo15MinuteWindowCache(message.Figi, "diffs_pirson", new Contracts.Declisions.Dtos.CachedValue()
{
Time = message.Time,
Count = resv,
Price = resdp,
Value = (decimal)pirson,
});
if (diffs.TryCalcPirsonCorrelation(meanWindow, out var pirson))
var diffs_pirson = await _tradeDataProvider.GetDataFrom15MinuteWindowCache(message.Figi, "diffs_pirson");
if (diffs_pirson.TryCalcTimeWindowsDiff(bigWindow, smallWindow, (c) => c.Value, true, out var res))
{
await LogPrice(message, "diffs_pirson", (decimal)pirson);
await _tradeDataProvider.AddDataTo15MinuteWindowCache(message.Figi, "diffs_pirson", new Contracts.Declisions.Dtos.CachedValue()
if (DPirsonValues.TryGetValue(message.Figi, out var olddpirs))
{
Time = message.Time,
Count = (decimal)pirson,
});
var diffs_pirson = await _tradeDataProvider.GetDataFrom15MinuteWindowCache(message.Figi, "diffs_pirson");
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))
if (olddpirs < 0.5m && res > 0.5m)
{
if (olddpirs < 0 && res > 0)
{
await LogPrice(message, "diffs_pirson_diff_point0", message.Value);
}
if (olddpirs < 0.25m && res > 0.25m)
{
await LogPrice(message, "diffs_pirson_diff_point0.25", message.Value);
}
if (olddpirs < 0.5m && res > 0.5m)
{
await LogPrice(message, "diffs_pirson_diff_point0.5", message.Value);
}
await LogPrice(message, "diffs_pirson_diff_point0.5", message.Price);
}
DPirsonValues[message.Figi] = res;
}
DPirsonValues[message.Figi] = res;
}
}
}
if (timesCache.TryGetValue(message.Figi, out var dt))
{
if ((message.Time - dt).TotalSeconds > 10)
{
timesCache[message.Figi] = message.Time;
var newMod = await CalcTradingMode2(message);
if (TradingModes.TryGetValue(message.Figi, out var oldMod))
{
if ((oldMod == TradingMode.Growing || oldMod == TradingMode.Stable)
&& oldMod != newMod)
{
changeMods[TradingEvent.UptrendEnd] = Constants.PowerUppingCoefficient;
}
if ((oldMod == TradingMode.Dropping || oldMod == TradingMode.SlowDropping)
&& oldMod != newMod)
{
changeMods[TradingEvent.DowntrendEnd] = Constants.PowerUppingCoefficient;
}
if (newMod == TradingMode.Growing && newMod != oldMod && !LongOpeningStops.ContainsKey(message.Figi))
{
//changeMods[TradingEvent.UptrendStart] = Constants.PowerUppingCoefficient;
}
if (newMod == TradingMode.Dropping && newMod != oldMod && !ShortOpeningStops.ContainsKey(message.Figi))
{
//changeMods[TradingEvent.DowntrendStart] = Constants.PowerUppingCoefficient;
}
TradingModes[message.Figi] = newMod;
if (oldMod != newMod)
{
var accountForStopsChanging = _portfolioWrapper.Accounts
.Where(a => a.Value.Assets.ContainsKey(message.Figi))
.ToArray();
foreach (var account in accountForStopsChanging)
{
if (account.Value.Assets.TryGetValue(message.Figi, out var asset))
{
var stops = GetStops(message, asset.Count > 0 ? PositionType.Long : PositionType.Short);
if (!message.IsHistoricalData)
{
await account.Value.ResetStops(message.Figi, stops.stopLoss, stops.takeProfit);
if (asset.Count < 0)
{
await LogDeclision(DeclisionTradeAction.ResetStopsShort, asset.BoughtPrice - stops.takeProfit, message.Time.AddMilliseconds(-100), message);
await LogDeclision(DeclisionTradeAction.ResetStopsShort, asset.BoughtPrice + stops.stopLoss, message.Time.AddMilliseconds(100), message);
}
else
{
await LogDeclision(DeclisionTradeAction.ResetStopsLong, asset.BoughtPrice + stops.takeProfit, message.Time.AddMilliseconds(-100), message);
await LogDeclision(DeclisionTradeAction.ResetStopsLong, asset.BoughtPrice - stops.stopLoss, message.Time.AddMilliseconds(100), message);
}
}
}
}
}
}
}
}
else
{
timesCache[message.Figi] = message.Time;
}
}
catch (Exception ex)
{
}
if (TradingModes.TryGetValue(message.Figi, out var mode))
{
await LogPrice(message, "trading_mode", (decimal)mode);
}
try
{
if (message.Direction != 1) continue;
await _tradeDataProvider.AddData(message);
//ProcessStops(message, currentTime);
var windowMaxSize = 2000;
//var data = await _tradeDataProvider.GetData(message.Figi, windowMaxSize);
//var state = ExchangeScheduler.GetCurrentState(message.Time);
// await ProcessNewPriceIMOEXF3(data, state, message, windowMaxSize, changeMods.ToImmutableDictionary());
}
catch (Exception ex)
{
_logger.LogError(ex, "Ошибка при боработке новой цены IMOEXF");
}
}
}
catch (Exception e)
catch (Exception ex)
{
_logger.LogError(ex, "Ошибка при боработке новой цены.");
}
}
}
private async Task ClosePositions(Asset[] assets, INewPrice message, bool withProfitOnly = true)
{
var loggedDeclisions = 0;
var assetType = _tradeDataProvider.GetAssetTypeByFigi(message.Figi);
var assetsForClose = new List<Asset>();
var price = message.Value;
var price = message.Price;
if (price == 0)
{
price = await _tradeDataProvider.GetLastPrice(message.Figi);
@ -381,6 +275,8 @@ namespace KLHZ.Trader.Core.Exchange.Services
var messages = new List<string>();
foreach (var asset in assets)
{
Asset? assetForClose = null;
string? mess = null;
if (withProfitOnly)
{
var profit = 0m;
@ -405,8 +301,8 @@ namespace KLHZ.Trader.Core.Exchange.Services
if (profit > 0)
{
profit = System.Math.Round(profit, 2);
assetsForClose.Add(asset);
messages.Add($"Закрываю позицию {asset.Figi} ({(asset.Count > 0 ? "лонг" : "шорт")}) на счёте {_portfolioWrapper.Accounts[asset.AccountId].AccountName}. Количество {(long)asset.Count}, цена ~{price}, профит {profit}");
assetForClose = asset;
mess = $"Закрываю позицию {asset.Figi} ({(asset.Count > 0 ? "лонг" : "шорт")}) на счёте {_portfolioWrapper.Accounts[asset.AccountId].AccountName}. Количество {(long)asset.Count}, цена ~{price}, профит {profit}";
if (loggedDeclisions == 0)
{
loggedDeclisions++;
@ -416,16 +312,15 @@ namespace KLHZ.Trader.Core.Exchange.Services
}
else
{
messages.Add($"Закрываю позицию {asset.Figi} ({(asset.Count > 0 ? "лонг" : "шорт")}) на счёте {_portfolioWrapper.Accounts[asset.AccountId].AccountName}. Количество {(long)asset.Count}, цена ~{price}");
assetsForClose.Add(asset);
mess = $"Закрываю позицию {asset.Figi} ({(asset.Count > 0 ? "лонг" : "шорт")}) на счёте {_portfolioWrapper.Accounts[asset.AccountId].AccountName}. Количество {(long)asset.Count}, цена ~{price}";
assetForClose = asset;
}
}
for (int i = 0; i < assetsForClose.Count; i++)
{
var asset = assetsForClose[i];
await _portfolioWrapper.Accounts[asset.AccountId].ClosePosition(message.Figi);
await _dataBus.Broadcast(new MessageForAdmin() { Text = messages[i] });
if (assetForClose != null && mess != null)
{
await _portfolioWrapper.Accounts[asset.AccountId].ClosePosition(message.Figi);
await _dataBus.Broadcast(new MessageForAdmin() { Text = mess });
}
}
}
@ -435,14 +330,14 @@ namespace KLHZ.Trader.Core.Exchange.Services
var sign = positionType == PositionType.Long ? 1 : 1;
foreach (var acc in accounts)
{
if (TraderUtils.IsOperationAllowed(acc, message.Value, 1, _exchangeConfig.AccountCashPartFutures, _exchangeConfig.AccountCashPart))
if (TraderUtils.IsOperationAllowed(acc, message.Price, 1, _exchangeConfig.AccountCashPartFutures, _exchangeConfig.AccountCashPart))
{
await acc.OpenPosition(message.Figi, positionType, stopLossShift, takeProfitShift, count);
await _dataBus.Broadcast(new MessageForAdmin()
{
Text = $"Открываю позицию {message.Figi} ({(positionType == PositionType.Long ? "лонг" : "шорт")}) " +
$"на счёте {acc.AccountName}. Количество {(positionType == PositionType.Long ? "" : "-")}{count}, " +
$"цена ~{System.Math.Round(message.Value, 2)}. Стоп лосс: {(positionType == PositionType.Long ? "-" : "+")}{stopLossShift}. " +
$"цена ~{System.Math.Round(message.Price, 2)}. Стоп лосс: {(positionType == PositionType.Long ? "-" : "+")}{stopLossShift}. " +
$"Тейк профит: {(positionType == PositionType.Long ? "+" : "-")}{takeProfitShift}"
});
}
@ -450,7 +345,6 @@ namespace KLHZ.Trader.Core.Exchange.Services
if (loggedDeclisions == 0)
{
await LogDeclision(DeclisionTradeAction.OpenLongReal, message);
LongOpeningStops[message.Figi] = message.Time.AddMinutes(1);
loggedDeclisions++;
}
}
@ -460,7 +354,6 @@ namespace KLHZ.Trader.Core.Exchange.Services
{
var state = ExchangeScheduler.GetCurrentState();
if (result[TradingEvent.UptrendStart] >= Constants.UppingCoefficient
&& !LongOpeningStops.ContainsKey(message.Figi)
&& state == ExchangeState.Open
)
{
@ -473,16 +366,14 @@ namespace KLHZ.Trader.Core.Exchange.Services
.Select(a => a.Value)
.ToArray();
await OpenPositions(accounts, message, PositionType.Long, stops.stopLoss, stops.takeProfit, 1);
LongOpeningStops[message.Figi] = DateTime.UtcNow.AddMinutes(1);
}
await LogDeclision(DeclisionTradeAction.OpenLong, message.Value, message.Time.AddMilliseconds(RandomNumberGenerator.GetInt32(-100, 100)), message);
await LogDeclision(DeclisionTradeAction.ResetStopsLong, message.Value + stops.takeProfit, message.Time.AddMilliseconds(-RandomNumberGenerator.GetInt32(300, 1000)), message);
await LogDeclision(DeclisionTradeAction.ResetStopsLong, message.Value - stops.stopLoss, message.Time.AddMilliseconds(RandomNumberGenerator.GetInt32(300, 1000)), message);
await LogDeclision(DeclisionTradeAction.OpenLong, message.Price, message.Time.AddMilliseconds(RandomNumberGenerator.GetInt32(-100, 100)), message);
await LogDeclision(DeclisionTradeAction.ResetStopsLong, message.Price + stops.takeProfit, message.Time.AddMilliseconds(-RandomNumberGenerator.GetInt32(300, 1000)), message);
await LogDeclision(DeclisionTradeAction.ResetStopsLong, message.Price - stops.stopLoss, message.Time.AddMilliseconds(RandomNumberGenerator.GetInt32(300, 1000)), message);
}
if (result[TradingEvent.DowntrendStart] >= Constants.UppingCoefficient
&& !ShortOpeningStops.ContainsKey(message.Figi)
&& state == ExchangeState.Open
)
)
{
var stops = GetStops(message, PositionType.Short);
if (!message.IsHistoricalData && BotModeSwitcher.CanPurchase())
@ -493,12 +384,11 @@ namespace KLHZ.Trader.Core.Exchange.Services
.Select(a => a.Value)
.ToArray();
await OpenPositions(accounts, message, PositionType.Short, stops.stopLoss, stops.takeProfit, 1);
ShortOpeningStops[message.Figi] = DateTime.UtcNow.AddMinutes(1);
}
await LogDeclision(DeclisionTradeAction.OpenShort, message.Value, message.Time.AddMilliseconds(RandomNumberGenerator.GetInt32(-100, 100)), message);
await LogDeclision(DeclisionTradeAction.ResetStopsShort, message.Value - stops.takeProfit, message.Time.AddMilliseconds(-RandomNumberGenerator.GetInt32(300, 1000)), message);
await LogDeclision(DeclisionTradeAction.ResetStopsShort, message.Value + stops.stopLoss, message.Time.AddMilliseconds(RandomNumberGenerator.GetInt32(300, 1000)), message);
await LogDeclision(DeclisionTradeAction.OpenShort, message.Price, message.Time.AddMilliseconds(RandomNumberGenerator.GetInt32(-100, 100)), message);
await LogDeclision(DeclisionTradeAction.ResetStopsShort, message.Price - stops.takeProfit, message.Time.AddMilliseconds(-RandomNumberGenerator.GetInt32(300, 1000)), message);
await LogDeclision(DeclisionTradeAction.ResetStopsShort, message.Price + stops.stopLoss, message.Time.AddMilliseconds(RandomNumberGenerator.GetInt32(300, 1000)), message);
}
if (result[TradingEvent.UptrendEnd] >= Constants.UppingCoefficient * 10)
{
@ -510,7 +400,7 @@ namespace KLHZ.Trader.Core.Exchange.Services
.ToArray();
await ClosePositions(assetsForClose, message);
}
await LogDeclision(DeclisionTradeAction.CloseLong, message.Value, message.Time.AddMilliseconds(RandomNumberGenerator.GetInt32(-100, 100)), message);
await LogDeclision(DeclisionTradeAction.CloseLong, message.Price, message.Time.AddMilliseconds(RandomNumberGenerator.GetInt32(-100, 100)), message);
}
@ -524,43 +414,11 @@ namespace KLHZ.Trader.Core.Exchange.Services
.ToArray();
await ClosePositions(assetsForClose, message);
}
await LogDeclision(DeclisionTradeAction.CloseShort, message.Value, message.Time.AddMilliseconds(RandomNumberGenerator.GetInt32(-100, 100)), message);
await LogDeclision(DeclisionTradeAction.CloseShort, message.Price, message.Time.AddMilliseconds(RandomNumberGenerator.GetInt32(-100, 100)), message);
}
}
private void ProcessStops(INewPrice message, DateTime currentTime)
{
if (LongOpeningStops.TryGetValue(message.Figi, out var dt))
{
if (dt < currentTime)
{
LongOpeningStops.TryRemove(message.Figi, out _);
}
}
if (ShortClosingStops.TryGetValue(message.Figi, out var dt2))
{
if (dt2 < currentTime)
{
ShortClosingStops.TryRemove(message.Figi, out _);
}
}
if (LongClosingStops.TryGetValue(message.Figi, out var dt3))
{
if (dt3 < currentTime)
{
LongClosingStops.TryRemove(message.Figi, out _);
}
}
if (ShortOpeningStops.TryGetValue(message.Figi, out var dt4))
{
if (dt4 < currentTime)
{
ShortOpeningStops.TryRemove(message.Figi, out _);
}
}
}
private async Task LogPrice(INewPrice message, string processor, decimal value)
{
await _tradeDataProvider.LogPrice(new ProcessedPrice()
@ -569,7 +427,7 @@ namespace KLHZ.Trader.Core.Exchange.Services
Ticker = message.Ticker,
Processor = processor,
Time = message.Time,
Value = value,
Price = value,
}, false);
}
@ -581,7 +439,7 @@ namespace KLHZ.Trader.Core.Exchange.Services
Ticker = ticker,
Processor = processor,
Time = time,
Value = value,
Price = value,
}, false);
}
@ -593,7 +451,7 @@ namespace KLHZ.Trader.Core.Exchange.Services
Figi = message.Figi,
Ticker = message.Ticker,
Value = profit,
Price = message.Value,
Price = message.Price,
Time = message.IsHistoricalData ? message.Time : DateTime.UtcNow,
Action = action,
}, false);
@ -645,135 +503,11 @@ namespace KLHZ.Trader.Core.Exchange.Services
return res;
}
private async ValueTask<TradingMode> CalcTradingMode2(INewPrice message)
{
var res = TradingMode.None;
var data = await _tradeDataProvider.GetData(message.Figi, TimeSpan.FromMinutes(20));
if (data.isFullIntervalExists)
{
if (LocalTrends.TryCalcTrendDiff(data.timestamps, data.prices, out var diff))
{
if (diff >= -2 && diff <= 2)
{
res = TradingMode.Stable;
}
else if (diff < -6)
{
res = TradingMode.Dropping;
}
else if (diff > 6)
{
res = TradingMode.Growing;
}
else if (diff < -2)
{
res = TradingMode.SlowDropping;
}
else if (diff > 2)
{
res = TradingMode.SlowGrowing;
}
}
}
return res;
}
private (decimal stopLoss, decimal takeProfit) GetStops(INewPrice message, PositionType type)
{
var mode = TradingModes[message.Figi];
decimal stopLossShift = 2m;
decimal takeProfitShift = 6;
if (mode == TradingMode.Growing && type == PositionType.Long)
{
takeProfitShift = 15;
//stopLossShift = 2;
}
if (mode == TradingMode.Growing && type == PositionType.Short)
{
//stopLossShift = 2;
takeProfitShift = 3m;
}
if (mode == TradingMode.Stable && type == PositionType.Long)
{
takeProfitShift = 3m;
}
if (mode == TradingMode.Stable && type == PositionType.Short)
{
takeProfitShift = 3m;
//stopLossShift = 10;
}
if (mode == TradingMode.SlowDropping && type == PositionType.Short)
{
}
if (mode == TradingMode.SlowDropping && type == PositionType.Long)
{
takeProfitShift = 1.5m;
//stopLossShift = 10;
}
if (mode == TradingMode.SlowGrowing && type == PositionType.Short)
{
//takeProfitShift = 2.5m;
//stopLossShift = 10;
}
if (mode == TradingMode.SlowGrowing && type == PositionType.Long)
{
}
if (mode == TradingMode.Dropping && type == PositionType.Short)
{
takeProfitShift = 15;
//stopLossShift = 2;
}
if (mode == TradingMode.Dropping && type == PositionType.Long)
{
//stopLossShift = 2;
takeProfitShift = 3m;
}
return (stopLossShift, takeProfitShift);
}
private Task<ImmutableDictionary<TradingEvent, decimal>> GetTradingModeMods(INewPrice message)
{
var res = TraderUtils.GetInitDict(1);
var mode = TradingModes[message.Figi];
if (mode == TradingMode.None)
{
//res[TradingEvent.UptrendEnd] = Constants.UppingCoefficient;
//res[TradingEvent.UptrendStart] = 1;
res[TradingEvent.DowntrendStart] = Constants.LowingCoefficient;
//res[TradingEvent.DowntrendEnd] = Constants.UppingCoefficient;
}
if (mode == TradingMode.Growing)
{
//res[TradingEvent.UptrendEnd] = Constants.LowingCoefficient;
res[TradingEvent.UptrendStart] = Constants.UppingCoefficient;
res[TradingEvent.DowntrendStart] = Constants.BlockingCoefficient;
res[TradingEvent.DowntrendEnd] = Constants.PowerUppingCoefficient;
}
if (mode == TradingMode.Stable)
{
//res[TradingEvent.UptrendEnd] = 1;
res[TradingEvent.UptrendStart] = Constants.LowingCoefficient;
//res[TradingEvent.DowntrendEnd] = Constants.UppingCoefficient;
res[TradingEvent.DowntrendStart] = Constants.LowingCoefficient;
}
if (mode == TradingMode.SlowDropping)
{
//res[TradingEvent.UptrendEnd] = Constants.PowerUppingCoefficient;
//res[TradingEvent.UptrendStart] = Constants.LowingCoefficient;
res[TradingEvent.DowntrendStart] = Constants.UppingCoefficient;
//res[TradingEvent.DowntrendEnd] = Constants.UppingCoefficient;
}
if (mode == TradingMode.Dropping)
{
res[TradingEvent.UptrendEnd] = Constants.PowerUppingCoefficient;
res[TradingEvent.UptrendStart] = Constants.BlockingCoefficient;
res[TradingEvent.DowntrendStart] = Constants.UppingCoefficient;
//res[TradingEvent.DowntrendEnd] = Constants.LowingCoefficient;
}
return Task.FromResult(res.ToImmutableDictionary());
}
}
}

View File

@ -9,7 +9,6 @@ using KLHZ.Trader.Core.DataLayer.Entities.Prices;
using KLHZ.Trader.Core.Exchange.Models.Configs;
using KLHZ.Trader.Core.Math.Declisions.Dtos.FFT;
using KLHZ.Trader.Core.Math.Declisions.Services.Cache;
using KLHZ.Trader.Core.Math.Declisions.Utils;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
@ -241,7 +240,7 @@ namespace KLHZ.Trader.Core.Exchange.Services
Figi = c.Figi,
Ticker = c.Ticker,
Time = c.Time,
Value = c.Value,
Price = c.Price,
IsHistoricalData = true,
Direction = c.Direction,
Count = c.Count,
@ -251,15 +250,6 @@ namespace KLHZ.Trader.Core.Exchange.Services
foreach (var price in data)
{
await AddData(price);
var cachedData = await GetData(price.Figi);
if ((DateTime.UtcNow - price.Time).TotalMinutes < 5)
{
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, Count = (decimal)rel });
}
}
}
}

View File

@ -82,7 +82,7 @@ namespace KLHZ.Trader.Core.Exchange.Utils
Direction = message.Direction,
IsHistoricalData = message.IsHistoricalData,
Time = message.Time,
Value = list.Sum(l => l.Value) / list.Count
Price = list.Sum(l => l.Price) / list.Count
};
list.Clear();
return message;

View File

@ -2,9 +2,6 @@ using KLHZ.Trader.Core.Contracts.Messaging.Dtos;
using KLHZ.Trader.Core.Contracts.Messaging.Interfaces;
using KLHZ.Trader.Core.DataLayer;
using KLHZ.Trader.Core.DataLayer.Entities.Orders;
using KLHZ.Trader.Core.DataLayer.Entities.Prices;
using KLHZ.Trader.Core.Exchange.Services;
using KLHZ.Trader.Core.Math.Declisions.Utils;
using KLHZ.Trader.Service.Models;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
@ -15,15 +12,13 @@ namespace KLHZ.Trader.Service.Controllers
[Route("[controller]/[action]")]
public class PlayController : ControllerBase
{
private readonly TraderDataProvider _traderDataProvider;
private readonly IDataBus _dataBus;
private readonly IDbContextFactory<TraderDbContext> _dbContextFactory;
public PlayController(IDataBus dataBus, IDbContextFactory<TraderDbContext> dbContextFactory, TraderDataProvider traderDataProvider)
public PlayController(IDataBus dataBus, IDbContextFactory<TraderDbContext> dbContextFactory)
{
_dbContextFactory = dbContextFactory;
_dataBus = dataBus;
_traderDataProvider = traderDataProvider;
}
[HttpGet]
@ -59,7 +54,7 @@ namespace KLHZ.Trader.Service.Controllers
Figi = c.Figi,
Ticker = c.Ticker,
Time = c.Time,
Value = c.Value,
Price = c.Price,
IsHistoricalData = true,
Direction = c.Direction,
Count = c.Count,
@ -239,334 +234,6 @@ namespace KLHZ.Trader.Service.Controllers
}
}
[HttpGet]
public async Task CalcOrderbookMeanav(string figi)
{
try
{
var t = DateTime.UtcNow.AddHours(-4);
using var context1 = await _dbContextFactory.CreateDbContextAsync();
context1.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking;
var data = await context1.OrderbookItems
.Where(i => i.Time > t && i.Figi == figi && (i.ItemType == Core.DataLayer.Entities.Orders.Enums.OrderbookItemType.BidsSummary4 || i.ItemType == Core.DataLayer.Entities.Orders.Enums.OrderbookItemType.AsksSummary4))
.OrderBy(i => i.Time)
.ToArrayAsync();
var bids = new LinkedList<OrderbookItem>();
var asks = new LinkedList<OrderbookItem>();
var buffer = new List<OrderbookItem>();
var dt = TimeSpan.FromMinutes(1);
var q = data.ToLookup(d => d.Time);
foreach (var d in q)
{
var pair = d.DistinctBy(www => www.ItemType).OrderBy(www => www.ItemType).ToArray();
if (pair.Length == 2)
{
bids.AddLast(pair[1]);
if (bids.Last().Time - bids.First().Time > dt)
{
bids.RemoveFirst();
}
if (pair[0].Count != 0)
{
pair[1].Price = ((decimal)pair[1].Count) / ((decimal)pair[0].Count);
buffer.Add(new OrderbookItem()
{
Figi = pair[1].Figi,
Ticker = pair[1].Ticker,
Count = 1,
ItemType = Core.DataLayer.Entities.Orders.Enums.OrderbookItemType.BidsAsksSummary4_2min,
Price = bids.Sum(b => b.Price) / bids.Count,
Time = pair[1].Time,
});
}
if (buffer.Count > 10000)
{
await context1.OrderbookItems.AddRangeAsync(buffer);
await context1.SaveChangesAsync();
buffer.Clear();
}
}
else
{
}
}
if (buffer.Count > 0)
{
await context1.OrderbookItems.AddRangeAsync(buffer);
await context1.SaveChangesAsync();
buffer.Clear();
}
}
catch (Exception ex)
{
}
}
[HttpGet]
public async Task CalcTradesMeanav(string figi)
{
try
{
var t = DateTime.UtcNow.AddHours(-4);
using var context1 = await _dbContextFactory.CreateDbContextAsync();
context1.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking;
var data = await context1.PriceChanges
.Where(i => i.Time > t && i.Figi == figi)
.OrderBy(i => i.Time)
.ToArrayAsync();
var sells = new LinkedList<PriceChange>();
var buys = new LinkedList<PriceChange>();
var buffer = new List<ProcessedPrice>();
var dt = TimeSpan.FromMinutes(1);
foreach (var d in data)
{
if (d.Direction == 1)
{
if (buys.Last().Time - buys.First().Time > dt)
{
buys.RemoveFirst();
}
buys.AddLast(d);
}
if (d.Direction == 2)
{
sells.AddLast(d);
if (sells.Last().Time - sells.First().Time > dt)
{
sells.RemoveFirst();
}
sells.AddLast(d);
}
if (sells.Count > 0 && buys.Count > 0)
{
var meanS = ((decimal)sells.Sum(s => s.Count)) / sells.Count;
var meanB = ((decimal)buys.Sum(s => s.Count)) / buys.Count;
if (meanS != 0)
{
buffer.Add(new ProcessedPrice()
{
Figi = d.Figi,
Processor = "tradesbalance",
Ticker = d.Ticker,
Count = 1,
Direction = 0,
Time = d.Time,
Value = meanB / meanS
});
}
}
if (buffer.Count > 10000)
{
await context1.ProcessedPrices.AddRangeAsync(buffer);
await context1.SaveChangesAsync();
buffer.Clear();
}
}
if (buffer.Count > 0)
{
await context1.ProcessedPrices.AddRangeAsync(buffer);
await context1.SaveChangesAsync();
buffer.Clear();
}
}
catch (Exception ex)
{
}
}
[HttpGet]
public async Task TestInmterpolate(string figi)
{
try
{
var t1 = DateTime.UtcNow.AddHours(-4);
var t2 = DateTime.UtcNow.AddHours(1);
//t1 = new DateTime(2025, 9, 15, 10, 1, 0, DateTimeKind.Utc);
//t2 = new DateTime(2025, 9, 15, 10, 1, 50, DateTimeKind.Utc);
using var context1 = await _dbContextFactory.CreateDbContextAsync();
context1.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking;
var data = await context1.PriceChanges
.Where(i => i.Time >= t1 && i.Time <= t2 && i.Figi == figi)
.OrderBy(i => i.Time)
.ToArrayAsync();
var buffer = new List<ProcessedPrice>();
var res = SignalProcessing.InterpolateData(data.Select(d => d.Time).ToArray(), data.Select(d => d.Value).ToArray(),
TimeSpan.FromSeconds(1));
for (int i = 0; i < res.Item1.Length; i++)
{
buffer.Add(new ProcessedPrice()
{
Figi = figi,
Processor = "1secinterpol",
Ticker = data[0].Ticker,
Count = 1,
Direction = 0,
Time = res.Item1[i],
Value = (decimal)res.Item2[i]
});
}
await context1.ProcessedPrices.AddRangeAsync(buffer);
await context1.SaveChangesAsync();
}
catch (Exception ex)
{
}
}
[HttpGet]
public async Task TestFFT(string figi)
{
try
{
var t1 = new DateTime(2025, 9, 15, 6, 30, 0, DateTimeKind.Utc);
var t2 = new DateTime(2025, 9, 15, 7, 50, 50, DateTimeKind.Utc);
using var context1 = await _dbContextFactory.CreateDbContextAsync();
context1.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking;
var data = await context1.PriceChanges
.Where(i => i.Time >= t1 && i.Time <= t2 && i.Figi == figi)
.OrderBy(i => i.Time)
.ToArrayAsync();
var buffer = new List<ProcessedPrice>();
var values = data.Select(d => d.Value).ToArray();
var times = data.Select(d => d.Time).ToArray();
var res = SignalProcessing.InterpolateData(times, values,
TimeSpan.FromSeconds(10));
//FFT.GetMainHarmonictPeriod(res.Item2, res.Item1.Last() - res.Item1.First());
}
catch (Exception ex)
{
}
}
//[HttpGet]
//public async Task GetBalance(string figi)
//{
// try
// {
// var time1 = DateTime.UtcNow.AddDays(-7);
// using var context1 = await _dbContextFactory.CreateDbContextAsync();
// context1.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking;
// var data = await context1.PriceChanges
// .Where(c => c.Figi == figi && c.Time >= time1)
// .OrderBy(c => c.Time)
// .Select(c => new NewPriceMessage()
// {
// Figi = figi,
// Ticker = c.Ticker,
// Time = c.Time,
// Value = c.Value,
// IsHistoricalData = true
// })
// .ToArrayAsync();
// var buffer = new List<ProcessedPrice>();
// var list = new LinkedList<(DateTime time, double value)>();
// var previous = -1000d;
// foreach (var mess in data)
// {
// await _traderDataProvider.AddData(mess, TimeSpan.FromHours(6));
// var dataFromCache = await _traderDataProvider.GetData(figi, TimeSpan.FromMinutes(15));
// if (dataFromCache.isFullIntervalExists)
// {
// if (ShapeAreaCalculator.TryGetAreasRelation(dataFromCache.timestamps, dataFromCache.prices,mess.Value,out var res))
// {
// if (list.Count > 0 && mess.Time - list.Last().time > TimeSpan.FromMinutes(5))
// {
// list.Clear();
// }
// list.AddLast((mess.Time, res));
// if (list.Last().time - list.First().time > TimeSpan.FromMinutes(1))
// {
// list.RemoveFirst();
// }
// var newRes = (decimal)(list.Sum(i => i.value) / list.Count);
// if (list.Count > 0)
// {
// try
// {
// buffer.Add(new ProcessedPrice()
// {
// Figi = figi,
// Processor = "balancescalc30min",
// Ticker = mess.Ticker,
// Time = mess.Time,
// Value = newRes,
// //Value = (decimal)res,
// });
// }
// catch(Exception ex)
// {
// }
// }
// }
// }
// else
// {
// previous = -1d;
// }
// if (buffer.Count > 10000)
// {
// await context1.ProcessedPrices.AddRangeAsync(buffer);
// await context1.SaveChangesAsync();
// buffer.Clear();
// }
// }
// if (buffer.Count > 0)
// {
// await context1.ProcessedPrices.AddRangeAsync(buffer);
// await context1.SaveChangesAsync();
// buffer.Clear();
// }
// }
// catch (Exception ex)
// {
// }
//}
////[HttpGet]
//public async Task LoadTradesToHistory(string figi)
//{
// try
// {
// using var context1 = await _dbContextFactory.CreateDbContextAsync();
// context1.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking;
// var data = await context1.InstrumentTrades
// .Where(c => c.Figi == figi)
// .OrderBy(c => c.BoughtAt)
// .Select(c => new PriceChange()
// {
// Figi = figi,
// Ticker = c.Ticker,
// Time = c.BoughtAt,
// Value = c.Price,
// IsHistoricalData = true
// })
// .ToArrayAsync();
// await context1.PriceChanges.Where(p => p.Figi == figi).ExecuteDeleteAsync();
// await context1.PriceChanges.AddRangeAsync(data);
// await context1.SaveChangesAsync();
// }
// catch (Exception ex)
// {
// }
//}
}
}

View File

@ -2,7 +2,7 @@
namespace KLHZ.Trader.Service.Models
{
public class TimeSeriesData
internal class TimeSeriesData
{
public required string Figi { get; set; }
public DateTime Time { get; set; }

View File

@ -8,7 +8,6 @@
},
"LokiUrl": "",
"ExchangeConfig": {
"StopBuyLengthMinuts": 15,
"ExchangeDataRecievingEnabled": true,
"Token": "",
"ManagingAccountNamePatterns": [ "автотрейд" ],
@ -18,7 +17,6 @@
"ShareComission": 0.0004,
"AccountCashPart": 0.05,
"AccountCashPartFutures": 0.5,
"DefaultBuyPartOfAccount": 0.3333,
"InstrumentsSettings": [
{
"Figi": "FUTIMOEXF000",