Чистка кода
parent
00de5bee2e
commit
64c702ebf1
|
@ -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; }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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; }
|
||||
}
|
||||
}
|
|
@ -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; }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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; }
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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)));
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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; }
|
||||
|
|
|
@ -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; }
|
||||
|
|
|
@ -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; } = [];
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
// {
|
||||
|
||||
// }
|
||||
//}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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; }
|
||||
|
|
|
@ -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",
|
||||
|
|
Loading…
Reference in New Issue