оптимизация кэша
test / deploy_trader_prod (push) Successful in 4m32s
Details
test / deploy_trader_prod (push) Successful in 4m32s
Details
parent
7424cdd5ca
commit
8d329dc069
|
@ -7,7 +7,6 @@ namespace KLHZ.Trader.Core.Contracts.Declisions.Interfaces
|
||||||
public string Figi { get; }
|
public string Figi { get; }
|
||||||
public int Length { get; }
|
public int Length { get; }
|
||||||
public ValueTask AddData(INewPrice priceChange);
|
public ValueTask AddData(INewPrice priceChange);
|
||||||
|
|
||||||
public ValueTask<(DateTime[] timestamps, float[] prices)> GetData();
|
public ValueTask<(DateTime[] timestamps, float[] prices)> GetData();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,191 +0,0 @@
|
||||||
using KLHZ.Trader.Core.Contracts.Messaging.Dtos.Intarfaces;
|
|
||||||
using KLHZ.Trader.Core.Contracts.Messaging.Interfaces;
|
|
||||||
using MathNet.Filtering.Kalman;
|
|
||||||
using MathNet.Numerics.LinearAlgebra;
|
|
||||||
using Microsoft.Extensions.Hosting;
|
|
||||||
using System.Threading.Channels;
|
|
||||||
|
|
||||||
namespace KLHZ.Trader.Core.Math.Declisions.Dtos.Services
|
|
||||||
{
|
|
||||||
public class KalmanPredictor : IHostedService
|
|
||||||
{
|
|
||||||
private readonly double r = 1000.0; // Measurement covariance
|
|
||||||
private readonly PriceHistoryCacheUnit _cache = new PriceHistoryCacheUnit("");
|
|
||||||
private readonly Channel<INewPrice> _messages = Channel.CreateUnbounded<INewPrice>();
|
|
||||||
private readonly IDataBus _dataBus;
|
|
||||||
|
|
||||||
private DiscreteKalmanFilter? _dkf;
|
|
||||||
|
|
||||||
public KalmanPredictor(IDataBus bus)
|
|
||||||
{
|
|
||||||
_dataBus = bus;
|
|
||||||
bus.AddChannel(nameof(KalmanPredictor), _messages);
|
|
||||||
_ = ProcessMessages();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Task StartAsync(CancellationToken cancellationToken)
|
|
||||||
{
|
|
||||||
return Task.CompletedTask;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Task StopAsync(CancellationToken cancellationToken)
|
|
||||||
{
|
|
||||||
return Task.CompletedTask;
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task Init()
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task ProcessCalman(INewPrice message)
|
|
||||||
{
|
|
||||||
var H = Matrix<double>.Build.Dense(2, 2, new[] { 1d, 0d, 0d, 1d }); // Measurement matrix
|
|
||||||
var length = _cache.Length;
|
|
||||||
|
|
||||||
if (length > 2 && _dkf != null)
|
|
||||||
{
|
|
||||||
var data = await _cache.GetData();
|
|
||||||
|
|
||||||
var dt = (data.timestamps[data.prices.Length - 1] - data.timestamps[data.prices.Length - 2]).TotalSeconds;
|
|
||||||
if (dt < 0.0000001 || dt > 1800) return;
|
|
||||||
var F = Matrix<double>.Build.Dense(2, 2, new[] { 1d, 0d, dt, 1 }); // State transition matrix
|
|
||||||
var R = Matrix<double>.Build.Dense(2, 2, new[] { r, r / dt, r / dt, 2 * r / (dt * dt) });
|
|
||||||
_dkf.Predict(F);
|
|
||||||
|
|
||||||
var state = _dkf.State;
|
|
||||||
var value = state[0, 0] + dt * state[1, 0];
|
|
||||||
if (!double.IsNaN(value))
|
|
||||||
{
|
|
||||||
await _dataBus.BroadcastProcessedPrice(new ProcessedPrice()
|
|
||||||
{
|
|
||||||
Figi = message.Figi,
|
|
||||||
Processor = nameof(KalmanPredictor) + "_predict",
|
|
||||||
Ticker = message.Ticker,
|
|
||||||
IsHistoricalData = message.IsHistoricalData,
|
|
||||||
Time = message.Time,
|
|
||||||
Value = (decimal)value,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
var dprice = data.prices[data.prices.Length - 1] - data.prices[data.prices.Length - 2];
|
|
||||||
var k = dprice / dt;
|
|
||||||
var b = data.prices[data.prices.Length - 2];
|
|
||||||
var z = Matrix<double>.Build.Dense(2, 1, new[] { b, k });
|
|
||||||
|
|
||||||
_dkf.Update(z, H, R);
|
|
||||||
|
|
||||||
var state2 = _dkf.State;
|
|
||||||
var value2 = state2[0, 0] + dt * state2[1, 0];
|
|
||||||
if (!double.IsNaN(value))
|
|
||||||
{
|
|
||||||
await _dataBus.BroadcastProcessedPrice(new ProcessedPrice()
|
|
||||||
{
|
|
||||||
Figi = message.Figi,
|
|
||||||
Processor = nameof(KalmanPredictor) + "_state",
|
|
||||||
Ticker = message.Ticker,
|
|
||||||
IsHistoricalData = message.IsHistoricalData,
|
|
||||||
Time = message.Time,
|
|
||||||
Value = (decimal)value,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (length >= 2)
|
|
||||||
{
|
|
||||||
var data = await _cache.GetData();
|
|
||||||
var dprice = data.prices[data.prices.Length - 1] - data.prices[data.prices.Length - 2];
|
|
||||||
var dt = (data.timestamps[data.prices.Length - 1] - data.timestamps[data.prices.Length - 2]).TotalSeconds;
|
|
||||||
if (dt < 0.0000001) return;
|
|
||||||
var k = dprice / dt;
|
|
||||||
var b = data.prices[data.prices.Length - 2];
|
|
||||||
|
|
||||||
|
|
||||||
Matrix<double> x0 = Matrix<double>.Build.Dense(2, 1, new[] { b, k });
|
|
||||||
Matrix<double> P0 = Matrix<double>.Build.Dense(2, 2, new[] { r, r / dt, r / dt, 2 * r / (dt * dt) });
|
|
||||||
|
|
||||||
_dkf = new DiscreteKalmanFilter(x0, P0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task ProcessMovAv(INewPrice message, int window)
|
|
||||||
{
|
|
||||||
var data = await _cache.GetData();
|
|
||||||
if (data.prices.Length < window) return;
|
|
||||||
var sum = 0f;
|
|
||||||
var count = 0;
|
|
||||||
for (int i = 1; (i <= window); i++)
|
|
||||||
{
|
|
||||||
sum += data.prices[data.prices.Length - i];
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
|
|
||||||
await _dataBus.BroadcastProcessedPrice(new ProcessedPrice()
|
|
||||||
{
|
|
||||||
Figi = message.Figi,
|
|
||||||
Processor = nameof(KalmanPredictor) + "_mov_av_window" + window.ToString(),
|
|
||||||
Ticker = message.Ticker,
|
|
||||||
IsHistoricalData = message.IsHistoricalData,
|
|
||||||
Time = message.Time,
|
|
||||||
Value = (decimal)(sum / count),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task ProcessTimeWindow(INewPrice message, int window)
|
|
||||||
{
|
|
||||||
var data = await _cache.GetData();
|
|
||||||
var sum = data.prices[data.prices.Length - 1];
|
|
||||||
var count = 1;
|
|
||||||
var startTime = data.timestamps[data.prices.Length - 1];
|
|
||||||
for (int i = 2; (i < data.prices.Length && (startTime - data.timestamps[data.prices.Length - i]) < TimeSpan.FromSeconds(window)); i++)
|
|
||||||
{
|
|
||||||
sum += data.prices[data.prices.Length - i];
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
|
|
||||||
await _dataBus.BroadcastProcessedPrice(new ProcessedPrice()
|
|
||||||
{
|
|
||||||
Figi = message.Figi,
|
|
||||||
Processor = nameof(KalmanPredictor) + "_timeWindow" + window.ToString(),
|
|
||||||
Ticker = message.Ticker,
|
|
||||||
IsHistoricalData = message.IsHistoricalData,
|
|
||||||
Time = message.Time,
|
|
||||||
Value = (decimal)(sum / count),
|
|
||||||
});
|
|
||||||
|
|
||||||
var diffValue = System.Math.Abs((decimal)(sum / count) - message.Value);
|
|
||||||
await _dataBus.BroadcastProcessedPrice(new ProcessedPrice()
|
|
||||||
{
|
|
||||||
Figi = message.Figi,
|
|
||||||
Processor = nameof(KalmanPredictor) + "_diff" + window.ToString(),
|
|
||||||
Ticker = message.Ticker,
|
|
||||||
IsHistoricalData = message.IsHistoricalData,
|
|
||||||
Time = message.Time,
|
|
||||||
Value = diffValue > 3 ? diffValue : 0,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task ProcessMessages()
|
|
||||||
{
|
|
||||||
|
|
||||||
|
|
||||||
while (await _messages.Reader.WaitToReadAsync())
|
|
||||||
{
|
|
||||||
var message = await _messages.Reader.ReadAsync();
|
|
||||||
await _cache.AddData(message);
|
|
||||||
try
|
|
||||||
{
|
|
||||||
//await ProcessCalman(message);
|
|
||||||
await ProcessMovAv(message, 3);
|
|
||||||
await ProcessTimeWindow(message, 5);
|
|
||||||
await ProcessTimeWindow(message, 15);
|
|
||||||
await ProcessTimeWindow(message, 120);
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,319 @@
|
||||||
|
using KLHZ.Trader.Core.Contracts.Declisions.Dtos;
|
||||||
|
using KLHZ.Trader.Core.Contracts.Messaging.Dtos.Intarfaces;
|
||||||
|
using KLHZ.Trader.Core.Contracts.Messaging.Interfaces;
|
||||||
|
using KLHZ.Trader.Core.Math.Declisions.Dtos;
|
||||||
|
using MathNet.Filtering.Kalman;
|
||||||
|
using MathNet.Numerics.LinearAlgebra;
|
||||||
|
using Microsoft.Extensions.Hosting;
|
||||||
|
using System.Threading.Channels;
|
||||||
|
using static System.Runtime.InteropServices.JavaScript.JSType;
|
||||||
|
|
||||||
|
namespace KLHZ.Trader.Core.Math.Declisions.Services
|
||||||
|
{
|
||||||
|
public class KalmanPredictor : IHostedService
|
||||||
|
{
|
||||||
|
private readonly double r = 1000.0; // Measurement covariance
|
||||||
|
private readonly PriceHistoryCacheUnit _cache = new PriceHistoryCacheUnit("");
|
||||||
|
private readonly Channel<INewPrice> _messages = Channel.CreateUnbounded<INewPrice>();
|
||||||
|
private readonly IDataBus _dataBus;
|
||||||
|
|
||||||
|
private DiscreteKalmanFilter? _dkf;
|
||||||
|
|
||||||
|
public KalmanPredictor(IDataBus bus)
|
||||||
|
{
|
||||||
|
_dataBus = bus;
|
||||||
|
bus.AddChannel(nameof(KalmanPredictor), _messages);
|
||||||
|
_ = ProcessMessages();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task StartAsync(CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task StopAsync(CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task Init()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task ProcessCalman(INewPrice message)
|
||||||
|
{
|
||||||
|
var H = Matrix<double>.Build.Dense(2, 2, new[] { 1d, 0d, 0d, 1d }); // Measurement matrix
|
||||||
|
var length = _cache.Length;
|
||||||
|
|
||||||
|
if (length > 2 && _dkf != null)
|
||||||
|
{
|
||||||
|
var data = await _cache.GetData();
|
||||||
|
|
||||||
|
var dt = (data.timestamps[data.prices.Length - 1] - data.timestamps[data.prices.Length - 2]).TotalSeconds;
|
||||||
|
if (dt < 0.0000001 || dt > 1800) return;
|
||||||
|
var F = Matrix<double>.Build.Dense(2, 2, new[] { 1d, 0d, dt, 1 }); // State transition matrix
|
||||||
|
var R = Matrix<double>.Build.Dense(2, 2, new[] { r, r / dt, r / dt, 2 * r / (dt * dt) });
|
||||||
|
_dkf.Predict(F);
|
||||||
|
|
||||||
|
var state = _dkf.State;
|
||||||
|
var value = state[0, 0] + dt * state[1, 0];
|
||||||
|
if (!double.IsNaN(value))
|
||||||
|
{
|
||||||
|
await _dataBus.BroadcastProcessedPrice(new ProcessedPrice()
|
||||||
|
{
|
||||||
|
Figi = message.Figi,
|
||||||
|
Processor = nameof(KalmanPredictor) + "_predict",
|
||||||
|
Ticker = message.Ticker,
|
||||||
|
IsHistoricalData = message.IsHistoricalData,
|
||||||
|
Time = message.Time,
|
||||||
|
Value = (decimal)value,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
var dprice = data.prices[data.prices.Length - 1] - data.prices[data.prices.Length - 2];
|
||||||
|
var k = dprice / dt;
|
||||||
|
var b = data.prices[data.prices.Length - 2];
|
||||||
|
var z = Matrix<double>.Build.Dense(2, 1, new[] { b, k });
|
||||||
|
|
||||||
|
_dkf.Update(z, H, R);
|
||||||
|
|
||||||
|
var state2 = _dkf.State;
|
||||||
|
var value2 = state2[0, 0] + dt * state2[1, 0];
|
||||||
|
if (!double.IsNaN(value))
|
||||||
|
{
|
||||||
|
await _dataBus.BroadcastProcessedPrice(new ProcessedPrice()
|
||||||
|
{
|
||||||
|
Figi = message.Figi,
|
||||||
|
Processor = nameof(KalmanPredictor) + "_state",
|
||||||
|
Ticker = message.Ticker,
|
||||||
|
IsHistoricalData = message.IsHistoricalData,
|
||||||
|
Time = message.Time,
|
||||||
|
Value = (decimal)value,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (length >= 2)
|
||||||
|
{
|
||||||
|
var data = await _cache.GetData();
|
||||||
|
var dprice = data.prices[data.prices.Length - 1] - data.prices[data.prices.Length - 2];
|
||||||
|
var dt = (data.timestamps[data.prices.Length - 1] - data.timestamps[data.prices.Length - 2]).TotalSeconds;
|
||||||
|
if (dt < 0.0000001) return;
|
||||||
|
var k = dprice / dt;
|
||||||
|
var b = data.prices[data.prices.Length - 2];
|
||||||
|
|
||||||
|
|
||||||
|
Matrix<double> x0 = Matrix<double>.Build.Dense(2, 1, new[] { b, k });
|
||||||
|
Matrix<double> P0 = Matrix<double>.Build.Dense(2, 2, new[] { r, r / dt, r / dt, 2 * r / (dt * dt) });
|
||||||
|
|
||||||
|
_dkf = new DiscreteKalmanFilter(x0, P0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private async Task ProcessMovAv(INewPrice message, int window)
|
||||||
|
{
|
||||||
|
var data = await _cache.GetData();
|
||||||
|
if (data.prices.Length < window) return;
|
||||||
|
var sum = 0f;
|
||||||
|
var count = 0;
|
||||||
|
for (int i = 1; i <= window; i++)
|
||||||
|
{
|
||||||
|
sum += data.prices[data.prices.Length - i];
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
await _dataBus.BroadcastProcessedPrice(new ProcessedPrice()
|
||||||
|
{
|
||||||
|
Figi = message.Figi,
|
||||||
|
Processor = nameof(KalmanPredictor) + "_mov_av_window" + window.ToString(),
|
||||||
|
Ticker = message.Ticker,
|
||||||
|
IsHistoricalData = message.IsHistoricalData,
|
||||||
|
Time = message.Time,
|
||||||
|
Value = (decimal)(sum / count),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private static (DateTime time, float value) CalcTimeWindowAverageValue(DateTime[] timestamps, float[] values, int window, int shift = 0)
|
||||||
|
{
|
||||||
|
var sum = values[values.Length - 1 - shift];
|
||||||
|
var count = 1;
|
||||||
|
var startTime = timestamps[timestamps.Length - 1 - shift];
|
||||||
|
for (int i = 2; i < values.Length && startTime - timestamps[values.Length - i - shift] < TimeSpan.FromSeconds(window); i++)
|
||||||
|
{
|
||||||
|
sum += values[values.Length - i - shift];
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
return (startTime, sum / count);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static TradingEventsDto CheckByWindowAverageMean(DateTime[] timestamps, float[] prices, int size, float meanfullStep = 3f)
|
||||||
|
{
|
||||||
|
var twav15s = new float[size];
|
||||||
|
var twav120s = new float[size];
|
||||||
|
var times = new DateTime[size];
|
||||||
|
|
||||||
|
for (int shift = 0; shift < size; shift++)
|
||||||
|
{
|
||||||
|
var twav15 = CalcTimeWindowAverageValue(timestamps, prices, 15, shift);
|
||||||
|
var twav120 = CalcTimeWindowAverageValue(timestamps, prices, 120, shift);
|
||||||
|
twav15s[size - 1 - shift] = twav15.value;
|
||||||
|
twav120s[size - 1 - shift] = twav120.value;
|
||||||
|
times[size - 1 - shift] = twav120.time;
|
||||||
|
|
||||||
|
if (shift > 0)
|
||||||
|
{
|
||||||
|
var isCrossing = Utils.Lines.IsLinesCrossing(
|
||||||
|
times[size - 1 - shift],
|
||||||
|
times[size - 2 - shift],
|
||||||
|
twav15s[size - 1 - shift],
|
||||||
|
twav15s[size - 2 - shift],
|
||||||
|
twav120s[size - 1 - shift],
|
||||||
|
twav120s[size - 2 - shift]);
|
||||||
|
if (shift == 1 && !isCrossing) //если нет пересечения скользящих средний с окном 120 и 15 секунд между
|
||||||
|
//текущей и предыдущей точкой - можно не продолжать выполнение.
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (shift > 1 && isCrossing)
|
||||||
|
{
|
||||||
|
// если фильтрация окном 120 наползает на окно 15 сверху, потенциальное время открытия лонга и закрытия шорта
|
||||||
|
if (twav120s[size - 1] <= twav15s[size - 1] && twav120s[size - 2] > twav15s[size - 2] )
|
||||||
|
{
|
||||||
|
if (twav15s[size - 1 - shift] - twav15s[size - 1] >= meanfullStep)
|
||||||
|
{
|
||||||
|
return new TradingEventsDto(false, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// если фильтрация окном 15 наползает на окно 120 сверху, потенциальное время закрытия лонга и возможно открытия шорта
|
||||||
|
if (twav15s[size - 1] <= twav120s[size - 1] && twav15s[size - 2] > twav120s[size - 2])
|
||||||
|
{
|
||||||
|
if (twav15s[size - 1 - shift] - twav15s[size - 1] <= - meanfullStep)
|
||||||
|
{
|
||||||
|
return new TradingEventsDto(true, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return new TradingEventsDto(false, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task ProcessTimeWindow(INewPrice message, int window)
|
||||||
|
{
|
||||||
|
var data = await _cache.GetData();
|
||||||
|
var sum = data.prices[data.prices.Length - 1];
|
||||||
|
var count = 1;
|
||||||
|
var startTime = data.timestamps[data.prices.Length - 1];
|
||||||
|
for (int i = 2; i < data.prices.Length && startTime - data.timestamps[data.prices.Length - i] < TimeSpan.FromSeconds(window); i++)
|
||||||
|
{
|
||||||
|
sum += data.prices[data.prices.Length - i];
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
await _dataBus.BroadcastProcessedPrice(new ProcessedPrice()
|
||||||
|
{
|
||||||
|
Figi = message.Figi,
|
||||||
|
Processor = nameof(KalmanPredictor) + "_timeWindow" + window.ToString(),
|
||||||
|
Ticker = message.Ticker,
|
||||||
|
IsHistoricalData = message.IsHistoricalData,
|
||||||
|
Time = message.Time,
|
||||||
|
Value = (decimal)(sum / count),
|
||||||
|
});
|
||||||
|
|
||||||
|
var diffValue = System.Math.Abs((decimal)(sum / count) - message.Value);
|
||||||
|
await _dataBus.BroadcastProcessedPrice(new ProcessedPrice()
|
||||||
|
{
|
||||||
|
Figi = message.Figi,
|
||||||
|
Processor = nameof(KalmanPredictor) + "_diff" + window.ToString(),
|
||||||
|
Ticker = message.Ticker,
|
||||||
|
IsHistoricalData = message.IsHistoricalData,
|
||||||
|
Time = message.Time,
|
||||||
|
Value = diffValue > 3 ? diffValue : 0,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task ProcessMessages()
|
||||||
|
{
|
||||||
|
while (await _messages.Reader.WaitToReadAsync())
|
||||||
|
{
|
||||||
|
var message = await _messages.Reader.ReadAsync();
|
||||||
|
await _cache.AddData(message);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var data = await _cache.GetData();
|
||||||
|
|
||||||
|
|
||||||
|
var size = 50;
|
||||||
|
var twav15s = new float[size];
|
||||||
|
var twav120s = new float[size];
|
||||||
|
var times = new DateTime[size];
|
||||||
|
|
||||||
|
for (int shift = 0; shift < size; shift++)
|
||||||
|
{
|
||||||
|
var twav15 = CalcTimeWindowAverageValue(data.timestamps, data.prices, 15, shift);
|
||||||
|
var twav120 = CalcTimeWindowAverageValue(data.timestamps, data.prices, 120, shift);
|
||||||
|
twav15s[size - 1-shift] = twav15.value;
|
||||||
|
twav120s[size - 1 - shift] = twav120.value;
|
||||||
|
times[size - 1 - shift] = twav120.time;
|
||||||
|
|
||||||
|
if (shift>0)
|
||||||
|
{
|
||||||
|
var isCrossing = Utils.Lines.IsLinesCrossing(
|
||||||
|
times[size - 1 - shift],
|
||||||
|
times[size - 2 - shift],
|
||||||
|
twav15s[size - 1 - shift],
|
||||||
|
twav15s[size - 2 - shift],
|
||||||
|
twav120s[size - 1 - shift],
|
||||||
|
twav120s[size - 2 - shift]);
|
||||||
|
if (shift == 1 && !isCrossing) //если нет пересечения скользящих средний с окном 120 и 15 секунд между
|
||||||
|
//текущей и предыдущей точкой - можно не продолжать выполнение.
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (shift>1 && isCrossing)
|
||||||
|
{
|
||||||
|
// если фильтрация окном 120 наползает на окно 15 сверху, потенциальное время открытия лонга
|
||||||
|
if (twav120s[size - 1] <= twav15s[size - 1] && twav120s[size - 2] > twav15s[size - 2])
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// если фильтрация окном 15 наползает на окно 120 сверху, потенциальное время закрытия лонга и открытия шорта
|
||||||
|
if (twav15s[size - 1] <= twav120s[size - 1] && twav15s[size - 2] > twav120s[size - 2])
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//if (isCrossing && twav120_2 <= twav15_2)// если филтрация окном 120 наползает на окно 15 сверху, потенциальное время открытия лонга
|
||||||
|
//{
|
||||||
|
// for (int i=shift;i<111; i++)
|
||||||
|
// {
|
||||||
|
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
|
||||||
|
//if (isCrossing && twav15_2 <= twav120_2)// если филтрация окном 15 наползает на окно 120 сверху, потенциальное время закрытия лонга
|
||||||
|
//{
|
||||||
|
|
||||||
|
//}
|
||||||
|
|
||||||
|
//await ProcessCalman(message);
|
||||||
|
await ProcessMovAv(message, 3);
|
||||||
|
await ProcessTimeWindow(message, 5);
|
||||||
|
await ProcessTimeWindow(message, 15);
|
||||||
|
await ProcessTimeWindow(message, 120);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,11 +1,11 @@
|
||||||
using KLHZ.Trader.Core.Contracts.Declisions.Interfaces;
|
using KLHZ.Trader.Core.Contracts.Declisions.Interfaces;
|
||||||
using KLHZ.Trader.Core.Contracts.Messaging.Dtos.Intarfaces;
|
using KLHZ.Trader.Core.Contracts.Messaging.Dtos.Intarfaces;
|
||||||
|
|
||||||
namespace KLHZ.Trader.Core.Math.Declisions.Dtos.Services
|
namespace KLHZ.Trader.Core.Math.Declisions.Services
|
||||||
{
|
{
|
||||||
public class PriceHistoryCacheUnit : IPriceHistoryCacheUnit
|
public class PriceHistoryCacheUnit : IPriceHistoryCacheUnit
|
||||||
{
|
{
|
||||||
public const int ArrayMaxLength = 500;
|
public const int CacheMaxLength = 500;
|
||||||
|
|
||||||
public string Figi { get; init; }
|
public string Figi { get; init; }
|
||||||
|
|
||||||
|
@ -21,8 +21,8 @@ namespace KLHZ.Trader.Core.Math.Declisions.Dtos.Services
|
||||||
}
|
}
|
||||||
|
|
||||||
private readonly object _locker = new();
|
private readonly object _locker = new();
|
||||||
private readonly float[] Prices = new float[ArrayMaxLength];
|
private readonly float[] Prices = new float[CacheMaxLength];
|
||||||
private readonly DateTime[] Timestamps = new DateTime[ArrayMaxLength];
|
private readonly DateTime[] Timestamps = new DateTime[CacheMaxLength];
|
||||||
|
|
||||||
private int _length = 0;
|
private int _length = 0;
|
||||||
|
|
||||||
|
@ -36,7 +36,7 @@ namespace KLHZ.Trader.Core.Math.Declisions.Dtos.Services
|
||||||
Prices[Prices.Length - 1] = (float)priceChange.Value;
|
Prices[Prices.Length - 1] = (float)priceChange.Value;
|
||||||
Timestamps[Timestamps.Length - 1] = priceChange.Time;
|
Timestamps[Timestamps.Length - 1] = priceChange.Time;
|
||||||
|
|
||||||
if (_length < ArrayMaxLength)
|
if (_length < CacheMaxLength)
|
||||||
{
|
{
|
||||||
_length++;
|
_length++;
|
||||||
}
|
}
|
||||||
|
@ -68,7 +68,7 @@ namespace KLHZ.Trader.Core.Math.Declisions.Dtos.Services
|
||||||
|
|
||||||
var selectedPriceChanges = priceChanges
|
var selectedPriceChanges = priceChanges
|
||||||
.OrderBy(pc => pc.Time)
|
.OrderBy(pc => pc.Time)
|
||||||
.Skip(priceChanges.Length - ArrayMaxLength)
|
.Skip(priceChanges.Length - CacheMaxLength)
|
||||||
.ToArray();
|
.ToArray();
|
||||||
var prices = selectedPriceChanges
|
var prices = selectedPriceChanges
|
||||||
.Select(pc => (float)pc.Value)
|
.Select(pc => (float)pc.Value)
|
||||||
|
@ -80,7 +80,7 @@ namespace KLHZ.Trader.Core.Math.Declisions.Dtos.Services
|
||||||
Array.Copy(prices, 0, Prices, Prices.Length - prices.Length, prices.Length);
|
Array.Copy(prices, 0, Prices, Prices.Length - prices.Length, prices.Length);
|
||||||
Array.Copy(times, 0, Timestamps, Timestamps.Length - times.Length, times.Length);
|
Array.Copy(times, 0, Timestamps, Timestamps.Length - times.Length, times.Length);
|
||||||
|
|
||||||
_length = times.Length > ArrayMaxLength ? ArrayMaxLength : times.Length;
|
_length = times.Length > CacheMaxLength ? CacheMaxLength : times.Length;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -0,0 +1,94 @@
|
||||||
|
using KLHZ.Trader.Core.Contracts.Declisions.Interfaces;
|
||||||
|
using KLHZ.Trader.Core.Contracts.Messaging.Dtos.Intarfaces;
|
||||||
|
using System.Reflection;
|
||||||
|
|
||||||
|
namespace KLHZ.Trader.Core.Math.Declisions.Services
|
||||||
|
{
|
||||||
|
public class PriceHistoryCacheUnit2 : IPriceHistoryCacheUnit
|
||||||
|
{
|
||||||
|
public const int CacheMaxLength = 500;
|
||||||
|
private const int _arrayMaxLength = 1500;
|
||||||
|
|
||||||
|
public string Figi { get; init; }
|
||||||
|
|
||||||
|
public int Length
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
lock (_locker)
|
||||||
|
{
|
||||||
|
return _length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private readonly object _locker = new();
|
||||||
|
private readonly float[] Prices = new float[_arrayMaxLength];
|
||||||
|
private readonly DateTime[] Timestamps = new DateTime[_arrayMaxLength];
|
||||||
|
|
||||||
|
private int _length = 0;
|
||||||
|
private int _pointer = -1;
|
||||||
|
|
||||||
|
public ValueTask AddData(INewPrice priceChange)
|
||||||
|
{
|
||||||
|
lock (_locker)
|
||||||
|
{
|
||||||
|
_pointer++;
|
||||||
|
Prices[_pointer] = (float)priceChange.Value;
|
||||||
|
Timestamps[_pointer] = priceChange.Time;
|
||||||
|
if (_length < CacheMaxLength)
|
||||||
|
{
|
||||||
|
_length++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_pointer == _arrayMaxLength - 1)
|
||||||
|
{
|
||||||
|
Array.Copy(Prices, Prices.Length - CacheMaxLength, Prices, 0, CacheMaxLength);
|
||||||
|
Array.Copy(Timestamps, Timestamps.Length - CacheMaxLength, Timestamps, 0, CacheMaxLength);
|
||||||
|
_pointer = CacheMaxLength - 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ValueTask.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ValueTask<(DateTime[] timestamps, float[] prices)> GetData()
|
||||||
|
{
|
||||||
|
lock (_locker)
|
||||||
|
{
|
||||||
|
if (_pointer < 0)
|
||||||
|
{
|
||||||
|
return ValueTask.FromResult((Array.Empty<DateTime>(), Array.Empty <float>()));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var prices = new float[_length];
|
||||||
|
var timestamps = new DateTime[_length];
|
||||||
|
Array.Copy(Prices,1+ _pointer - _length, prices, 0, prices.Length);
|
||||||
|
Array.Copy(Timestamps,1+ _pointer - _length, timestamps, 0, timestamps.Length);
|
||||||
|
return ValueTask.FromResult((timestamps, prices));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public PriceHistoryCacheUnit2(string figi, params INewPrice[] priceChanges)
|
||||||
|
{
|
||||||
|
Figi = figi;
|
||||||
|
|
||||||
|
|
||||||
|
if (priceChanges.Length == 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var selectedPriceChanges = priceChanges
|
||||||
|
.OrderBy(pc => pc.Time)
|
||||||
|
.Skip(priceChanges.Length - CacheMaxLength)
|
||||||
|
.ToArray();
|
||||||
|
|
||||||
|
foreach ( var pc in selectedPriceChanges)
|
||||||
|
{
|
||||||
|
AddData(pc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -8,6 +8,7 @@
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="MathNet.Filtering.Kalman" Version="0.7.0" />
|
<PackageReference Include="MathNet.Filtering.Kalman" Version="0.7.0" />
|
||||||
|
<PackageReference Include="MathNet.Numerics" Version="5.0.0" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="9.0.8" />
|
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="9.0.8" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,34 @@
|
||||||
|
namespace KLHZ.Trader.Core.Math.Utils
|
||||||
|
{
|
||||||
|
public static class Lines
|
||||||
|
{
|
||||||
|
public static (float x, float y) LinesCrossing(float k1, float b1, float k2, float b2)
|
||||||
|
{
|
||||||
|
var x = (b2 - b1) / (k1 - k2);
|
||||||
|
var y = k1 * x + b1;
|
||||||
|
|
||||||
|
return (x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool IsLinesCrossing(DateTime time1, DateTime time2, float val1_1, float val1_2, float val2_1, float val2_2)
|
||||||
|
{
|
||||||
|
var dtime = (float)(time2 - time1).TotalSeconds;
|
||||||
|
|
||||||
|
var dval1 = (val1_2 - val1_1);
|
||||||
|
var k1 = dval1 / dtime;
|
||||||
|
var b1 = val1_1;
|
||||||
|
|
||||||
|
var dval2 = val2_2 - val2_1;
|
||||||
|
var k2 = dval2 / dtime;
|
||||||
|
var b2 = val2_1;
|
||||||
|
|
||||||
|
if (k1 != k2)
|
||||||
|
{
|
||||||
|
var cross = LinesCrossing(k1, b1, k2, b2);
|
||||||
|
var crossingTimestamp = time1.AddSeconds(cross.x);
|
||||||
|
return crossingTimestamp >= time1 && crossingTimestamp <= time2;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,223 @@
|
||||||
|
using KLHZ.Trader.Core.DataLayer.Entities.Prices;
|
||||||
|
using KLHZ.Trader.Core.Math.Declisions.Services;
|
||||||
|
|
||||||
|
namespace KLHZ.Trader.Core.Tests
|
||||||
|
{
|
||||||
|
public class HistoryCacheUnit2Tests
|
||||||
|
{
|
||||||
|
private static PriceChange[] GetHistory(int count, string figi)
|
||||||
|
{
|
||||||
|
var res = new PriceChange[count];
|
||||||
|
if (count != 0)
|
||||||
|
{
|
||||||
|
var startDt = DateTime.UtcNow.AddSeconds(-count);
|
||||||
|
for (int i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
startDt = startDt.AddSeconds(i);
|
||||||
|
res[i] = new PriceChange()
|
||||||
|
{
|
||||||
|
Figi = figi,
|
||||||
|
Ticker = figi + "_ticker",
|
||||||
|
Id = i,
|
||||||
|
Time = startDt,
|
||||||
|
Value = (decimal)(i + 0.5)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void Test1()
|
||||||
|
{
|
||||||
|
var count = 0;
|
||||||
|
var figi = "figi";
|
||||||
|
var hist = GetHistory(count, figi);
|
||||||
|
var cacheUnit = new PriceHistoryCacheUnit2("", hist);
|
||||||
|
var data = cacheUnit.GetData().Result;
|
||||||
|
|
||||||
|
Assert.That(data.prices.Length == count);
|
||||||
|
Assert.That(data.timestamps.Length == count);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void Test2()
|
||||||
|
{
|
||||||
|
var count = 1;
|
||||||
|
var figi = "figi";
|
||||||
|
var hist = GetHistory(count, figi);
|
||||||
|
var cacheUnit = new PriceHistoryCacheUnit2("", hist);
|
||||||
|
var data = cacheUnit.GetData().Result;
|
||||||
|
|
||||||
|
Assert.That(data.prices.Length == count);
|
||||||
|
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(hist[i].Time, Is.EqualTo(data.timestamps[i]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void Test3()
|
||||||
|
{
|
||||||
|
var count = 20;
|
||||||
|
var figi = "figi";
|
||||||
|
var hist = GetHistory(count, figi);
|
||||||
|
var cacheUnit = new PriceHistoryCacheUnit2("", hist);
|
||||||
|
var data = cacheUnit.GetData().Result;
|
||||||
|
|
||||||
|
Assert.That(data.prices.Length == count);
|
||||||
|
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(hist[i].Time, Is.EqualTo(data.timestamps[i]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void Test4()
|
||||||
|
{
|
||||||
|
var count = PriceHistoryCacheUnit.CacheMaxLength;
|
||||||
|
var figi = "figi";
|
||||||
|
var hist = GetHistory(count, figi);
|
||||||
|
var cacheUnit = new PriceHistoryCacheUnit2("", hist);
|
||||||
|
var data = cacheUnit.GetData().Result;
|
||||||
|
|
||||||
|
Assert.That(data.prices.Length == count);
|
||||||
|
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(hist[i].Time, Is.EqualTo(data.timestamps[i]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void Test5()
|
||||||
|
{
|
||||||
|
var shift = 7;
|
||||||
|
var count = PriceHistoryCacheUnit.CacheMaxLength + shift;
|
||||||
|
var figi = "figi";
|
||||||
|
var hist = GetHistory(count, figi);
|
||||||
|
var cacheUnit = new PriceHistoryCacheUnit2("", hist);
|
||||||
|
var data = cacheUnit.GetData().Result;
|
||||||
|
|
||||||
|
Assert.That(data.prices.Length == count - shift);
|
||||||
|
Assert.That(data.timestamps.Length == count - shift);
|
||||||
|
|
||||||
|
for (var i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
var k = i + shift;
|
||||||
|
if (k < hist.Length)
|
||||||
|
{
|
||||||
|
Assert.That((float)hist[k].Value, Is.EqualTo(data.prices[i]));
|
||||||
|
Assert.That(hist[k].Time, Is.EqualTo(data.timestamps[i]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void Test6()
|
||||||
|
{
|
||||||
|
var shift = 10;
|
||||||
|
var count = PriceHistoryCacheUnit.CacheMaxLength + shift;
|
||||||
|
var figi = "figi";
|
||||||
|
var hist = GetHistory(count, figi);
|
||||||
|
var cacheUnit = new PriceHistoryCacheUnit2("", hist);
|
||||||
|
var data = cacheUnit.GetData().Result;
|
||||||
|
|
||||||
|
Assert.That(data.prices.Length == count - shift);
|
||||||
|
Assert.That(data.timestamps.Length == count - shift);
|
||||||
|
|
||||||
|
for (var i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
var k = i + shift;
|
||||||
|
if (k < hist.Length)
|
||||||
|
{
|
||||||
|
Assert.That((float)hist[k].Value, Is.EqualTo(data.prices[i]));
|
||||||
|
Assert.That(hist[k].Time, Is.EqualTo(data.timestamps[i]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void Test7()
|
||||||
|
{
|
||||||
|
var shift = 334;
|
||||||
|
var count = PriceHistoryCacheUnit.CacheMaxLength + shift;
|
||||||
|
var figi = "figi";
|
||||||
|
var hist = GetHistory(count, figi);
|
||||||
|
var cacheUnit = new PriceHistoryCacheUnit2("", hist);
|
||||||
|
var data = cacheUnit.GetData().Result;
|
||||||
|
|
||||||
|
Assert.That(data.prices.Length == count - shift);
|
||||||
|
Assert.That(data.timestamps.Length == count - shift);
|
||||||
|
|
||||||
|
for (var i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
var k = i + shift;
|
||||||
|
if (k < hist.Length)
|
||||||
|
{
|
||||||
|
Assert.That((float)hist[k].Value, Is.EqualTo(data.prices[i]));
|
||||||
|
Assert.That(hist[k].Time, Is.EqualTo(data.timestamps[i]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void Test8()
|
||||||
|
{
|
||||||
|
var count = PriceHistoryCacheUnit.CacheMaxLength;
|
||||||
|
var figi = "figi";
|
||||||
|
var hist = GetHistory(count, figi);
|
||||||
|
var cacheUnit = new PriceHistoryCacheUnit2("", hist);
|
||||||
|
var data = cacheUnit.GetData().Result;
|
||||||
|
|
||||||
|
Assert.That(data.prices.Length == count);
|
||||||
|
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(hist[i].Time, Is.EqualTo(data.timestamps[i]));
|
||||||
|
}
|
||||||
|
|
||||||
|
var newData1 = new PriceChange() { Figi = figi, Ticker = figi, Value = 100500, Time = DateTime.UtcNow };
|
||||||
|
|
||||||
|
cacheUnit.AddData(newData1);
|
||||||
|
|
||||||
|
var data2 = cacheUnit.GetData().Result;
|
||||||
|
Assert.IsTrue(data2.prices[data2.prices.Length - 1] == (float)newData1.Value);
|
||||||
|
Assert.IsTrue(data2.timestamps[data2.timestamps.Length - 1] == newData1.Time);
|
||||||
|
|
||||||
|
var newData2 = new PriceChange() { Figi = figi, Ticker = figi, Value = 100501, Time = DateTime.UtcNow };
|
||||||
|
|
||||||
|
cacheUnit.AddData(newData2);
|
||||||
|
|
||||||
|
var data3 = cacheUnit.GetData().Result;
|
||||||
|
Assert.IsTrue(data3.prices[data3.prices.Length - 1] == (float)newData2.Value);
|
||||||
|
Assert.IsTrue(data3.timestamps[data3.timestamps.Length - 1] == newData2.Time);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void Test9()
|
||||||
|
{
|
||||||
|
var cacheUnit = new PriceHistoryCacheUnit2("");
|
||||||
|
for(int i= 0; i < 5*PriceHistoryCacheUnit2.CacheMaxLength; i++)
|
||||||
|
{
|
||||||
|
cacheUnit.AddData(new PriceChange() { Figi = "", Ticker = "", Value = i, Time = DateTime.UtcNow });
|
||||||
|
if (i >= 500)
|
||||||
|
{
|
||||||
|
var data = cacheUnit.GetData().Result;
|
||||||
|
Assert.IsTrue(data.prices.Length == PriceHistoryCacheUnit2.CacheMaxLength);
|
||||||
|
Assert.IsTrue(data.prices.Last() == i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,8 +1,9 @@
|
||||||
using KLHZ.Trader.Core.DataLayer.Entities.Prices;
|
using KLHZ.Trader.Core.DataLayer.Entities.Prices;
|
||||||
|
using KLHZ.Trader.Core.Math.Declisions.Services;
|
||||||
|
|
||||||
namespace KLHZ.Trader.Core.Tests
|
namespace KLHZ.Trader.Core.Tests
|
||||||
{
|
{
|
||||||
public class Tests
|
public class HistoryCacheUnitTests
|
||||||
{
|
{
|
||||||
private static PriceChange[] GetHistory(int count, string figi)
|
private static PriceChange[] GetHistory(int count, string figi)
|
||||||
{
|
{
|
||||||
|
@ -79,7 +80,7 @@ namespace KLHZ.Trader.Core.Tests
|
||||||
[Test]
|
[Test]
|
||||||
public void Test4()
|
public void Test4()
|
||||||
{
|
{
|
||||||
var count = PriceHistoryCacheUnit.ArrayMaxLength;
|
var count = PriceHistoryCacheUnit.CacheMaxLength;
|
||||||
var figi = "figi";
|
var figi = "figi";
|
||||||
var hist = GetHistory(count, figi);
|
var hist = GetHistory(count, figi);
|
||||||
var cacheUnit = new PriceHistoryCacheUnit("", hist);
|
var cacheUnit = new PriceHistoryCacheUnit("", hist);
|
||||||
|
@ -99,7 +100,7 @@ namespace KLHZ.Trader.Core.Tests
|
||||||
public void Test5()
|
public void Test5()
|
||||||
{
|
{
|
||||||
var shift = 7;
|
var shift = 7;
|
||||||
var count = PriceHistoryCacheUnit.ArrayMaxLength + shift;
|
var count = PriceHistoryCacheUnit.CacheMaxLength + shift;
|
||||||
var figi = "figi";
|
var figi = "figi";
|
||||||
var hist = GetHistory(count, figi);
|
var hist = GetHistory(count, figi);
|
||||||
var cacheUnit = new PriceHistoryCacheUnit("", hist);
|
var cacheUnit = new PriceHistoryCacheUnit("", hist);
|
||||||
|
@ -123,7 +124,7 @@ namespace KLHZ.Trader.Core.Tests
|
||||||
public void Test6()
|
public void Test6()
|
||||||
{
|
{
|
||||||
var shift = 10;
|
var shift = 10;
|
||||||
var count = PriceHistoryCacheUnit.ArrayMaxLength + shift;
|
var count = PriceHistoryCacheUnit.CacheMaxLength + shift;
|
||||||
var figi = "figi";
|
var figi = "figi";
|
||||||
var hist = GetHistory(count, figi);
|
var hist = GetHistory(count, figi);
|
||||||
var cacheUnit = new PriceHistoryCacheUnit("", hist);
|
var cacheUnit = new PriceHistoryCacheUnit("", hist);
|
||||||
|
@ -147,7 +148,7 @@ namespace KLHZ.Trader.Core.Tests
|
||||||
public void Test7()
|
public void Test7()
|
||||||
{
|
{
|
||||||
var shift = 334;
|
var shift = 334;
|
||||||
var count = PriceHistoryCacheUnit.ArrayMaxLength + shift;
|
var count = PriceHistoryCacheUnit.CacheMaxLength + shift;
|
||||||
var figi = "figi";
|
var figi = "figi";
|
||||||
var hist = GetHistory(count, figi);
|
var hist = GetHistory(count, figi);
|
||||||
var cacheUnit = new PriceHistoryCacheUnit("", hist);
|
var cacheUnit = new PriceHistoryCacheUnit("", hist);
|
||||||
|
@ -171,7 +172,7 @@ namespace KLHZ.Trader.Core.Tests
|
||||||
[Test]
|
[Test]
|
||||||
public void Test8()
|
public void Test8()
|
||||||
{
|
{
|
||||||
var count = PriceHistoryCacheUnit.ArrayMaxLength;
|
var count = PriceHistoryCacheUnit.CacheMaxLength;
|
||||||
var figi = "figi";
|
var figi = "figi";
|
||||||
var hist = GetHistory(count, figi);
|
var hist = GetHistory(count, figi);
|
||||||
var cacheUnit = new PriceHistoryCacheUnit("", hist);
|
var cacheUnit = new PriceHistoryCacheUnit("", hist);
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
using KLHZ.Trader.Core.DataLayer.Entities.Prices;
|
using KLHZ.Trader.Core.DataLayer.Entities.Prices;
|
||||||
using KLHZ.Trader.Core.Declisions.Utils;
|
using KLHZ.Trader.Core.Declisions.Utils;
|
||||||
|
using KLHZ.Trader.Core.Math.Declisions.Services;
|
||||||
|
|
||||||
namespace KLHZ.Trader.Core.Tests
|
namespace KLHZ.Trader.Core.Tests
|
||||||
{
|
{
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\KLHZ.Trader.Core.Math\KLHZ.Trader.Core.Math.csproj" />
|
||||||
<ProjectReference Include="..\KLHZ.Trader.Core\KLHZ.Trader.Core.csproj" />
|
<ProjectReference Include="..\KLHZ.Trader.Core\KLHZ.Trader.Core.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,35 @@
|
||||||
|
namespace KLHZ.Trader.Core.Tests
|
||||||
|
{
|
||||||
|
public class LinesProcessingTest
|
||||||
|
{
|
||||||
|
[Test]
|
||||||
|
public void Test1()
|
||||||
|
{
|
||||||
|
var time2 = DateTime.UtcNow;
|
||||||
|
var time1 = time2.AddSeconds(-20);
|
||||||
|
|
||||||
|
var val1_1 = 0.5f;
|
||||||
|
var val1_2 = -0.5f;
|
||||||
|
|
||||||
|
var val2_1 = -0.5f;
|
||||||
|
var val2_2 = 0.5f;
|
||||||
|
|
||||||
|
Assert.IsTrue(KLHZ.Trader.Core.Math.Utils.Lines.IsLinesCrossing(time1, time2, val1_1, val1_2, val2_1, val2_2));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void Test2()
|
||||||
|
{
|
||||||
|
var time2 = DateTime.UtcNow;
|
||||||
|
var time1 = time2.AddSeconds(-20);
|
||||||
|
|
||||||
|
var val1_1 = 0.5f;
|
||||||
|
var val1_2 = -0.5f;
|
||||||
|
|
||||||
|
var val2_1 = 0.5f;
|
||||||
|
var val2_2 = -0.5f;
|
||||||
|
|
||||||
|
Assert.IsFalse(KLHZ.Trader.Core.Math.Utils.Lines.IsLinesCrossing(time1, time2, val1_1, val1_2, val2_1, val2_2));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -26,8 +26,6 @@ namespace KLHZ.Trader.Core.Declisions.Services
|
||||||
|
|
||||||
private async Task ProcessMessages()
|
private async Task ProcessMessages()
|
||||||
{
|
{
|
||||||
using var context = await _dbContextFactory.CreateDbContextAsync();
|
|
||||||
context.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking;
|
|
||||||
var buffer = new List<DataLayer.Entities.Prices.ProcessedPrice>();
|
var buffer = new List<DataLayer.Entities.Prices.ProcessedPrice>();
|
||||||
var lastWrite = DateTime.UtcNow;
|
var lastWrite = DateTime.UtcNow;
|
||||||
while (await _channel.Reader.WaitToReadAsync())
|
while (await _channel.Reader.WaitToReadAsync())
|
||||||
|
@ -48,10 +46,12 @@ namespace KLHZ.Trader.Core.Declisions.Services
|
||||||
|
|
||||||
if (buffer.Count > 10000 || (DateTime.UtcNow - lastWrite) > TimeSpan.FromSeconds(5) || _channel.Reader.Count == 0)
|
if (buffer.Count > 10000 || (DateTime.UtcNow - lastWrite) > TimeSpan.FromSeconds(5) || _channel.Reader.Count == 0)
|
||||||
{
|
{
|
||||||
await context.AddRangeAsync(buffer);
|
|
||||||
await context.SaveChangesAsync();
|
|
||||||
buffer.Clear();
|
|
||||||
lastWrite = DateTime.UtcNow;
|
lastWrite = DateTime.UtcNow;
|
||||||
|
using var context = await _dbContextFactory.CreateDbContextAsync();
|
||||||
|
context.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking;
|
||||||
|
await context.AddRangeAsync(buffer);
|
||||||
|
buffer.Clear();
|
||||||
|
await context.SaveChangesAsync();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
|
|
|
@ -9,7 +9,7 @@ using KLHZ.Trader.Core.Exchange;
|
||||||
using KLHZ.Trader.Core.Exchange.Extentions;
|
using KLHZ.Trader.Core.Exchange.Extentions;
|
||||||
using KLHZ.Trader.Core.Exchange.Models;
|
using KLHZ.Trader.Core.Exchange.Models;
|
||||||
using KLHZ.Trader.Core.Exchange.Services;
|
using KLHZ.Trader.Core.Exchange.Services;
|
||||||
using KLHZ.Trader.Core.Math.Declisions.Dtos.Services;
|
using KLHZ.Trader.Core.Math.Declisions.Services;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Microsoft.Extensions.Hosting;
|
using Microsoft.Extensions.Hosting;
|
||||||
|
@ -100,7 +100,7 @@ namespace KLHZ.Trader.Core.Declisions.Services
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
data = new PriceHistoryCacheUnit(message.Figi, message);
|
data = new PriceHistoryCacheUnit2(message.Figi, message);
|
||||||
_historyCash.TryAdd(message.Figi, data);
|
_historyCash.TryAdd(message.Figi, data);
|
||||||
}
|
}
|
||||||
var result = await _tradingEventsDetector.Detect(data);
|
var result = await _tradingEventsDetector.Detect(data);
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
using KLHZ.Trader.Core.Contracts.Declisions.Interfaces;
|
using KLHZ.Trader.Core.Contracts.Declisions.Interfaces;
|
||||||
using KLHZ.Trader.Core.Declisions.Dtos;
|
using KLHZ.Trader.Core.Declisions.Dtos;
|
||||||
using KLHZ.Trader.Core.Math.Declisions.Dtos.Services;
|
using KLHZ.Trader.Core.Math.Declisions.Services;
|
||||||
|
|
||||||
namespace KLHZ.Trader.Core.Declisions.Utils
|
namespace KLHZ.Trader.Core.Declisions.Utils
|
||||||
{
|
{
|
||||||
|
|
|
@ -26,7 +26,8 @@ EndProject
|
||||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "postrgres", "postrgres", "{174A800A-6040-40CF-B331-8603E097CBAC}"
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "postrgres", "postrgres", "{174A800A-6040-40CF-B331-8603E097CBAC}"
|
||||||
ProjectSection(SolutionItems) = preProject
|
ProjectSection(SolutionItems) = preProject
|
||||||
KLHZ.Trader.Infrastructure\postgres\init.sql = KLHZ.Trader.Infrastructure\postgres\init.sql
|
KLHZ.Trader.Infrastructure\postgres\init.sql = KLHZ.Trader.Infrastructure\postgres\init.sql
|
||||||
migration1.sql = migration1.sql
|
KLHZ.Trader.Infrastructure\postgres\migration1.sql = KLHZ.Trader.Infrastructure\postgres\migration1.sql
|
||||||
|
KLHZ.Trader.Infrastructure\postgres\migration2.sql = KLHZ.Trader.Infrastructure\postgres\migration2.sql
|
||||||
EndProjectSection
|
EndProjectSection
|
||||||
EndProject
|
EndProject
|
||||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "loki", "loki", "{63D21DAF-FDF0-4F2D-A671-E9E59BB0CA5B}"
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "loki", "loki", "{63D21DAF-FDF0-4F2D-A671-E9E59BB0CA5B}"
|
||||||
|
|
Loading…
Reference in New Issue