рефакторинг: вынос контрактов в отдельный проект
test / deploy_trader_prod (push) Successful in 2m42s
Details
test / deploy_trader_prod (push) Successful in 2m42s
Details
parent
f6b98e949d
commit
2d6bc10ed8
|
@ -0,0 +1,16 @@
|
||||||
|
namespace KLHZ.Trader.Core.Contracts.Declisions.Dtos
|
||||||
|
{
|
||||||
|
public readonly struct TradingEventsDto
|
||||||
|
{
|
||||||
|
public readonly bool LongClose;
|
||||||
|
public readonly bool LongOpen;
|
||||||
|
|
||||||
|
public TradingEventsDto(bool longClose, bool longOpen)
|
||||||
|
{
|
||||||
|
LongClose = longClose;
|
||||||
|
LongOpen = longOpen;
|
||||||
|
}
|
||||||
|
|
||||||
|
public readonly static TradingEventsDto Empty = new TradingEventsDto(false, false);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
using KLHZ.Trader.Core.Contracts.Messaging.Dtos.Intarfaces;
|
||||||
|
|
||||||
|
namespace KLHZ.Trader.Core.Contracts.Declisions.Interfaces
|
||||||
|
{
|
||||||
|
public interface IPriceHistoryCacheUnit
|
||||||
|
{
|
||||||
|
public string Figi { get; }
|
||||||
|
public ValueTask AddData(INewPriceMessage priceChange);
|
||||||
|
|
||||||
|
public ValueTask<(DateTime[] timestamps, float[] prices)> GetData();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
using KLHZ.Trader.Core.Contracts.Declisions.Dtos;
|
||||||
|
|
||||||
|
namespace KLHZ.Trader.Core.Contracts.Declisions.Interfaces
|
||||||
|
{
|
||||||
|
public interface ITradingEventsDetector
|
||||||
|
{
|
||||||
|
public ValueTask<TradingEventsDto> Detect(IPriceHistoryCacheUnit unit);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
</Project>
|
|
@ -1,4 +1,4 @@
|
||||||
namespace KLHZ.Trader.Core.Common.Messaging.Contracts.Messages.Enums
|
namespace KLHZ.Trader.Core.Contracts.Messaging.Dtos.Enums
|
||||||
{
|
{
|
||||||
public enum TradeCommandType
|
public enum TradeCommandType
|
||||||
{
|
{
|
|
@ -0,0 +1,7 @@
|
||||||
|
namespace KLHZ.Trader.Core.Contracts.Messaging.Dtos.Intarfaces
|
||||||
|
{
|
||||||
|
public interface IMessage
|
||||||
|
{
|
||||||
|
public string Text { get; set; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
namespace KLHZ.Trader.Core.Common.Messaging.Contracts.Messages
|
namespace KLHZ.Trader.Core.Contracts.Messaging.Dtos.Intarfaces
|
||||||
{
|
{
|
||||||
public interface INewCandle
|
public interface INewCandle
|
||||||
{
|
{
|
|
@ -1,4 +1,4 @@
|
||||||
namespace KLHZ.Trader.Core.Common.Messaging.Contracts.Messages
|
namespace KLHZ.Trader.Core.Contracts.Messaging.Dtos.Intarfaces
|
||||||
{
|
{
|
||||||
public interface INewPriceMessage
|
public interface INewPriceMessage
|
||||||
{
|
{
|
|
@ -0,0 +1,9 @@
|
||||||
|
using KLHZ.Trader.Core.Contracts.Messaging.Dtos.Intarfaces;
|
||||||
|
|
||||||
|
namespace KLHZ.Trader.Core.Contracts.Messaging.Dtos
|
||||||
|
{
|
||||||
|
public class MessageForAdmin : IMessage
|
||||||
|
{
|
||||||
|
public required string Text { get; set; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,4 +1,6 @@
|
||||||
namespace KLHZ.Trader.Core.Common.Messaging.Contracts.Messages
|
using KLHZ.Trader.Core.Contracts.Messaging.Dtos.Intarfaces;
|
||||||
|
|
||||||
|
namespace KLHZ.Trader.Core.Contracts.Messaging.Dtos
|
||||||
{
|
{
|
||||||
public class NewPriceMessage : INewPriceMessage
|
public class NewPriceMessage : INewPriceMessage
|
||||||
{
|
{
|
|
@ -1,6 +1,6 @@
|
||||||
using KLHZ.Trader.Core.Common.Messaging.Contracts.Messages.Enums;
|
using KLHZ.Trader.Core.Contracts.Messaging.Dtos.Enums;
|
||||||
|
|
||||||
namespace KLHZ.Trader.Core.Common.Messaging.Contracts.Messages
|
namespace KLHZ.Trader.Core.Contracts.Messaging.Dtos
|
||||||
{
|
{
|
||||||
public class TradeCommand
|
public class TradeCommand
|
||||||
{
|
{
|
|
@ -1,22 +1,17 @@
|
||||||
using KLHZ.Trader.Core.Common.Messaging.Contracts.Messages;
|
using KLHZ.Trader.Core.Contracts.Messaging.Dtos;
|
||||||
|
using KLHZ.Trader.Core.Contracts.Messaging.Dtos.Intarfaces;
|
||||||
using System.Threading.Channels;
|
using System.Threading.Channels;
|
||||||
|
|
||||||
namespace KLHZ.Trader.Core.Common.Messaging.Contracts
|
namespace KLHZ.Trader.Core.Contracts.Messaging.Interfaces
|
||||||
{
|
{
|
||||||
public interface IDataBus
|
public interface IDataBus
|
||||||
{
|
{
|
||||||
public bool AddChannel(string key, Channel<INewPriceMessage> channel);
|
public bool AddChannel(string key, Channel<INewPriceMessage> channel);
|
||||||
|
|
||||||
public bool AddChannel(string key, Channel<TradeCommand> channel);
|
public bool AddChannel(string key, Channel<TradeCommand> channel);
|
||||||
|
public bool AddChannel(string key, Channel<IMessage> channel);
|
||||||
public bool AddChannel(string key, Channel<INewCandle> channel);
|
public bool AddChannel(string key, Channel<INewCandle> channel);
|
||||||
|
|
||||||
public bool AddChannel(Channel<MessageForAdmin> channel);
|
|
||||||
|
|
||||||
public Task BroadcastNewPrice(INewPriceMessage newPriceMessage);
|
public Task BroadcastNewPrice(INewPriceMessage newPriceMessage);
|
||||||
|
|
||||||
public Task BroadcastCommand(TradeCommand command);
|
public Task BroadcastCommand(TradeCommand command);
|
||||||
|
|
||||||
public Task BroadcastCommand(MessageForAdmin command);
|
|
||||||
public Task BroadcastNewCandle(INewCandle command);
|
public Task BroadcastNewCandle(INewCandle command);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,5 +1,5 @@
|
||||||
using KLHZ.Trader.Core.DataLayer.Entities.Prices;
|
using KLHZ.Trader.Core.DataLayer.Entities.Prices;
|
||||||
using KLHZ.Trader.Core.Declisions.Models;
|
using KLHZ.Trader.Core.Declisions.Services;
|
||||||
|
|
||||||
namespace KLHZ.Trader.Core.Tests
|
namespace KLHZ.Trader.Core.Tests
|
||||||
{
|
{
|
||||||
|
@ -34,7 +34,7 @@ namespace KLHZ.Trader.Core.Tests
|
||||||
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);
|
||||||
var data = cacheUnit.GetData();
|
var data = cacheUnit.GetData().Result;
|
||||||
|
|
||||||
Assert.That(data.prices.Length == count);
|
Assert.That(data.prices.Length == count);
|
||||||
Assert.That(data.timestamps.Length == count);
|
Assert.That(data.timestamps.Length == count);
|
||||||
|
@ -47,7 +47,7 @@ namespace KLHZ.Trader.Core.Tests
|
||||||
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);
|
||||||
var data = cacheUnit.GetData();
|
var data = cacheUnit.GetData().Result;
|
||||||
|
|
||||||
Assert.That(data.prices.Length == count);
|
Assert.That(data.prices.Length == count);
|
||||||
Assert.That(data.timestamps.Length == count);
|
Assert.That(data.timestamps.Length == count);
|
||||||
|
@ -65,7 +65,7 @@ namespace KLHZ.Trader.Core.Tests
|
||||||
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);
|
||||||
var data = cacheUnit.GetData();
|
var data = cacheUnit.GetData().Result;
|
||||||
|
|
||||||
Assert.That(data.prices.Length == count);
|
Assert.That(data.prices.Length == count);
|
||||||
Assert.That(data.timestamps.Length == count);
|
Assert.That(data.timestamps.Length == count);
|
||||||
|
@ -84,7 +84,7 @@ namespace KLHZ.Trader.Core.Tests
|
||||||
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);
|
||||||
var data = cacheUnit.GetData();
|
var data = cacheUnit.GetData().Result;
|
||||||
|
|
||||||
Assert.That(data.prices.Length == count);
|
Assert.That(data.prices.Length == count);
|
||||||
Assert.That(data.timestamps.Length == count);
|
Assert.That(data.timestamps.Length == count);
|
||||||
|
@ -104,7 +104,7 @@ namespace KLHZ.Trader.Core.Tests
|
||||||
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);
|
||||||
var data = cacheUnit.GetData();
|
var data = cacheUnit.GetData().Result;
|
||||||
|
|
||||||
Assert.That(data.prices.Length == count - shift);
|
Assert.That(data.prices.Length == count - shift);
|
||||||
Assert.That(data.timestamps.Length == count - shift);
|
Assert.That(data.timestamps.Length == count - shift);
|
||||||
|
@ -128,7 +128,7 @@ namespace KLHZ.Trader.Core.Tests
|
||||||
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);
|
||||||
var data = cacheUnit.GetData();
|
var data = cacheUnit.GetData().Result;
|
||||||
|
|
||||||
Assert.That(data.prices.Length == count - shift);
|
Assert.That(data.prices.Length == count - shift);
|
||||||
Assert.That(data.timestamps.Length == count - shift);
|
Assert.That(data.timestamps.Length == count - shift);
|
||||||
|
@ -152,7 +152,7 @@ namespace KLHZ.Trader.Core.Tests
|
||||||
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);
|
||||||
var data = cacheUnit.GetData();
|
var data = cacheUnit.GetData().Result;
|
||||||
|
|
||||||
Assert.That(data.prices.Length == count - shift);
|
Assert.That(data.prices.Length == count - shift);
|
||||||
Assert.That(data.timestamps.Length == count - shift);
|
Assert.That(data.timestamps.Length == count - shift);
|
||||||
|
@ -176,7 +176,7 @@ namespace KLHZ.Trader.Core.Tests
|
||||||
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);
|
||||||
var data = cacheUnit.GetData();
|
var data = cacheUnit.GetData().Result;
|
||||||
|
|
||||||
Assert.That(data.prices.Length == count);
|
Assert.That(data.prices.Length == count);
|
||||||
Assert.That(data.timestamps.Length == count);
|
Assert.That(data.timestamps.Length == count);
|
||||||
|
@ -191,7 +191,7 @@ namespace KLHZ.Trader.Core.Tests
|
||||||
|
|
||||||
cacheUnit.AddData(newData1);
|
cacheUnit.AddData(newData1);
|
||||||
|
|
||||||
var data2 = cacheUnit.GetData();
|
var data2 = cacheUnit.GetData().Result;
|
||||||
Assert.IsTrue(data2.prices[data2.prices.Length - 1] == (float)newData1.Value);
|
Assert.IsTrue(data2.prices[data2.prices.Length - 1] == (float)newData1.Value);
|
||||||
Assert.IsTrue(data2.timestamps[data2.timestamps.Length - 1] == newData1.Time);
|
Assert.IsTrue(data2.timestamps[data2.timestamps.Length - 1] == newData1.Time);
|
||||||
|
|
||||||
|
@ -199,7 +199,7 @@ namespace KLHZ.Trader.Core.Tests
|
||||||
|
|
||||||
cacheUnit.AddData(newData2);
|
cacheUnit.AddData(newData2);
|
||||||
|
|
||||||
var data3 = cacheUnit.GetData();
|
var data3 = cacheUnit.GetData().Result;
|
||||||
Assert.IsTrue(data3.prices[data3.prices.Length - 1] == (float)newData2.Value);
|
Assert.IsTrue(data3.prices[data3.prices.Length - 1] == (float)newData2.Value);
|
||||||
Assert.IsTrue(data3.timestamps[data3.timestamps.Length - 1] == newData2.Time);
|
Assert.IsTrue(data3.timestamps[data3.timestamps.Length - 1] == newData2.Time);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
using KLHZ.Trader.Core.DataLayer.Entities.Prices;
|
using KLHZ.Trader.Core.DataLayer.Entities.Prices;
|
||||||
using KLHZ.Trader.Core.Declisions.Models;
|
using KLHZ.Trader.Core.Declisions.Services;
|
||||||
using KLHZ.Trader.Core.Declisions.Utils;
|
using KLHZ.Trader.Core.Declisions.Utils;
|
||||||
|
|
||||||
namespace KLHZ.Trader.Core.Tests
|
namespace KLHZ.Trader.Core.Tests
|
||||||
|
@ -38,7 +38,7 @@ namespace KLHZ.Trader.Core.Tests
|
||||||
var startValue = 10;
|
var startValue = 10;
|
||||||
var unit = new PriceHistoryCacheUnit(figi, GetHistory(count, figi, startDate, startValue, step));
|
var unit = new PriceHistoryCacheUnit(figi, GetHistory(count, figi, startDate, startValue, step));
|
||||||
|
|
||||||
var data = unit.GetData();
|
var data = unit.GetData().Result;
|
||||||
var endDate = startDate.AddSeconds(count);
|
var endDate = startDate.AddSeconds(count);
|
||||||
Assert.IsTrue(data.timestamps.Last() == endDate);
|
Assert.IsTrue(data.timestamps.Last() == endDate);
|
||||||
Assert.IsTrue(data.prices.Last() == startValue + step * count);
|
Assert.IsTrue(data.prices.Last() == startValue + step * count);
|
||||||
|
@ -72,7 +72,7 @@ namespace KLHZ.Trader.Core.Tests
|
||||||
var startValue = 10;
|
var startValue = 10;
|
||||||
var unit = new PriceHistoryCacheUnit(figi, GetHistory(count, figi, startDate, startValue, step));
|
var unit = new PriceHistoryCacheUnit(figi, GetHistory(count, figi, startDate, startValue, step));
|
||||||
|
|
||||||
var data = unit.GetData();
|
var data = unit.GetData().Result;
|
||||||
var endDate = startDate.AddSeconds(count);
|
var endDate = startDate.AddSeconds(count);
|
||||||
Assert.IsTrue(data.timestamps.Last() == endDate);
|
Assert.IsTrue(data.timestamps.Last() == endDate);
|
||||||
Assert.IsTrue(data.prices.Last() == startValue + step * count);
|
Assert.IsTrue(data.prices.Last() == startValue + step * count);
|
||||||
|
@ -107,7 +107,7 @@ namespace KLHZ.Trader.Core.Tests
|
||||||
|
|
||||||
var unit = new PriceHistoryCacheUnit(figi, GetHistory(count, figi, startDate, startValue, step));
|
var unit = new PriceHistoryCacheUnit(figi, GetHistory(count, figi, startDate, startValue, step));
|
||||||
|
|
||||||
var data = unit.GetData();
|
var data = unit.GetData().Result;
|
||||||
var endDate = startDate.AddSeconds(count);
|
var endDate = startDate.AddSeconds(count);
|
||||||
Assert.IsTrue(data.timestamps.Last() == endDate);
|
Assert.IsTrue(data.timestamps.Last() == endDate);
|
||||||
Assert.IsTrue(data.prices.Last() == startValue + step * count);
|
Assert.IsTrue(data.prices.Last() == startValue + step * count);
|
||||||
|
@ -142,7 +142,7 @@ namespace KLHZ.Trader.Core.Tests
|
||||||
|
|
||||||
var unit = new PriceHistoryCacheUnit(figi, GetHistory(count, figi, startDate, startValue, step));
|
var unit = new PriceHistoryCacheUnit(figi, GetHistory(count, figi, startDate, startValue, step));
|
||||||
|
|
||||||
var data = unit.GetData();
|
var data = unit.GetData().Result;
|
||||||
var endDate = startDate.AddSeconds(count);
|
var endDate = startDate.AddSeconds(count);
|
||||||
Assert.IsTrue(data.timestamps.Last() == endDate);
|
Assert.IsTrue(data.timestamps.Last() == endDate);
|
||||||
Assert.IsTrue(data.prices.Last() == startValue + step * count);
|
Assert.IsTrue(data.prices.Last() == startValue + step * count);
|
||||||
|
@ -177,7 +177,7 @@ namespace KLHZ.Trader.Core.Tests
|
||||||
|
|
||||||
var unit = new PriceHistoryCacheUnit(figi, GetHistory(count, figi, startDate, startValue, step));
|
var unit = new PriceHistoryCacheUnit(figi, GetHistory(count, figi, startDate, startValue, step));
|
||||||
|
|
||||||
var data = unit.GetData();
|
var data = unit.GetData().Result;
|
||||||
var endDate = startDate.AddSeconds(count);
|
var endDate = startDate.AddSeconds(count);
|
||||||
Assert.IsTrue(data.timestamps.Last() == endDate);
|
Assert.IsTrue(data.timestamps.Last() == endDate);
|
||||||
Assert.IsTrue(data.prices.Last() == startValue + step * count);
|
Assert.IsTrue(data.prices.Last() == startValue + step * count);
|
||||||
|
@ -212,7 +212,7 @@ namespace KLHZ.Trader.Core.Tests
|
||||||
|
|
||||||
var unit = new PriceHistoryCacheUnit(figi, GetHistory(count, figi, startDate, startValue, step));
|
var unit = new PriceHistoryCacheUnit(figi, GetHistory(count, figi, startDate, startValue, step));
|
||||||
|
|
||||||
var data = unit.GetData();
|
var data = unit.GetData().Result;
|
||||||
var endDate = startDate.AddSeconds(count);
|
var endDate = startDate.AddSeconds(count);
|
||||||
Assert.IsTrue(data.timestamps.Last() == endDate);
|
Assert.IsTrue(data.timestamps.Last() == endDate);
|
||||||
Assert.IsTrue(data.prices.Last() == startValue + step * count);
|
Assert.IsTrue(data.prices.Last() == startValue + step * count);
|
||||||
|
@ -238,7 +238,7 @@ namespace KLHZ.Trader.Core.Tests
|
||||||
|
|
||||||
|
|
||||||
var unit2 = new PriceHistoryCacheUnit(figi);
|
var unit2 = new PriceHistoryCacheUnit(figi);
|
||||||
var data2 = unit.GetData();
|
var data2 = unit.GetData().Result;
|
||||||
for (int i = 0; i < data2.prices.Length; i++)
|
for (int i = 0; i < data2.prices.Length; i++)
|
||||||
{
|
{
|
||||||
var value = (decimal)data2.prices[i];
|
var value = (decimal)data2.prices[i];
|
||||||
|
|
|
@ -1,7 +0,0 @@
|
||||||
namespace KLHZ.Trader.Core.Common.Messaging.Contracts.Messages
|
|
||||||
{
|
|
||||||
public class MessageForAdmin
|
|
||||||
{
|
|
||||||
public required string Text { get; set; }
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,5 +1,6 @@
|
||||||
using KLHZ.Trader.Core.Common.Messaging.Contracts;
|
using KLHZ.Trader.Core.Contracts.Messaging.Dtos;
|
||||||
using KLHZ.Trader.Core.Common.Messaging.Contracts.Messages;
|
using KLHZ.Trader.Core.Contracts.Messaging.Dtos.Intarfaces;
|
||||||
|
using KLHZ.Trader.Core.Contracts.Messaging.Interfaces;
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using System.Threading.Channels;
|
using System.Threading.Channels;
|
||||||
|
|
||||||
|
@ -7,14 +8,14 @@ namespace KLHZ.Trader.Core.Common.Messaging.Services
|
||||||
{
|
{
|
||||||
public class DataBus : IDataBus
|
public class DataBus : IDataBus
|
||||||
{
|
{
|
||||||
|
private readonly ConcurrentDictionary<string, Channel<IMessage>> _messagesChannels = new();
|
||||||
private readonly ConcurrentDictionary<string, Channel<INewCandle>> _candlesChannels = new();
|
private readonly ConcurrentDictionary<string, Channel<INewCandle>> _candlesChannels = new();
|
||||||
private readonly ConcurrentDictionary<string, Channel<INewPriceMessage>> _priceChannels = new();
|
private readonly ConcurrentDictionary<string, Channel<INewPriceMessage>> _priceChannels = new();
|
||||||
private readonly ConcurrentDictionary<string, Channel<TradeCommand>> _commandChannels = new();
|
private readonly ConcurrentDictionary<string, Channel<TradeCommand>> _commandChannels = new();
|
||||||
private readonly ConcurrentDictionary<string, Channel<MessageForAdmin>> _chatMessages = new();
|
|
||||||
|
|
||||||
public bool AddChannel(Channel<MessageForAdmin> channel)
|
public bool AddChannel(string key, Channel<IMessage> channel)
|
||||||
{
|
{
|
||||||
return _chatMessages.TryAdd(Guid.NewGuid().ToString(), channel);
|
return _messagesChannels.TryAdd(key, channel);
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool AddChannel(string key, Channel<INewPriceMessage> channel)
|
public bool AddChannel(string key, Channel<INewPriceMessage> channel)
|
||||||
|
@ -55,13 +56,5 @@ namespace KLHZ.Trader.Core.Common.Messaging.Services
|
||||||
await channel.Writer.WriteAsync(command);
|
await channel.Writer.WriteAsync(command);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task BroadcastCommand(MessageForAdmin message)
|
|
||||||
{
|
|
||||||
foreach (var channel in _chatMessages.Values)
|
|
||||||
{
|
|
||||||
await channel.Writer.WriteAsync(message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
using KLHZ.Trader.Core.Common.Messaging.Contracts.Messages;
|
using KLHZ.Trader.Core.Contracts.Messaging.Dtos.Intarfaces;
|
||||||
using System.ComponentModel.DataAnnotations.Schema;
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
|
|
||||||
namespace KLHZ.Trader.Core.DataLayer.Entities.Prices
|
namespace KLHZ.Trader.Core.DataLayer.Entities.Prices
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
using KLHZ.Trader.Core.Common.Messaging.Contracts.Messages;
|
using KLHZ.Trader.Core.Contracts.Messaging.Dtos.Intarfaces;
|
||||||
using System.ComponentModel.DataAnnotations.Schema;
|
using System.ComponentModel.DataAnnotations.Schema;
|
||||||
|
|
||||||
namespace KLHZ.Trader.Core.DataLayer.Entities.Prices
|
namespace KLHZ.Trader.Core.DataLayer.Entities.Prices
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
namespace KLHZ.Trader.Core.Declisions.Models
|
namespace KLHZ.Trader.Core.Declisions.Dtos
|
||||||
{
|
{
|
||||||
public readonly struct PeriodPricesInfo
|
internal readonly struct PeriodPricesInfoDto
|
||||||
{
|
{
|
||||||
public readonly int Start;
|
public readonly int Start;
|
||||||
public readonly int End;
|
public readonly int End;
|
||||||
|
@ -12,7 +12,7 @@
|
||||||
public readonly bool Success;
|
public readonly bool Success;
|
||||||
public readonly TimeSpan Period;
|
public readonly TimeSpan Period;
|
||||||
|
|
||||||
public PeriodPricesInfo(bool success, float firstPrice, float lastPrice, float periodDiff, float periodMin, float periodMax, TimeSpan period, int start, int end)
|
public PeriodPricesInfoDto(bool success, float firstPrice, float lastPrice, float periodDiff, float periodMin, float periodMax, TimeSpan period, int start, int end)
|
||||||
{
|
{
|
||||||
Success = success;
|
Success = success;
|
||||||
LastPrice = lastPrice;
|
LastPrice = lastPrice;
|
|
@ -1,6 +1,6 @@
|
||||||
namespace KLHZ.Trader.Core.Declisions.Models
|
namespace KLHZ.Trader.Core.Declisions.Dtos
|
||||||
{
|
{
|
||||||
public readonly struct TwoPeriodsProcessingData
|
internal readonly struct TwoPeriodsProcessingDto
|
||||||
{
|
{
|
||||||
public readonly int Start;
|
public readonly int Start;
|
||||||
public readonly int Bound;
|
public readonly int Bound;
|
||||||
|
@ -11,7 +11,7 @@
|
||||||
public readonly TimeSpan PeriodStart;
|
public readonly TimeSpan PeriodStart;
|
||||||
public readonly TimeSpan PeriodEnd;
|
public readonly TimeSpan PeriodEnd;
|
||||||
|
|
||||||
public TwoPeriodsProcessingData(bool success, float diffStart, float diffEnd, int start, int bound, int end,
|
public TwoPeriodsProcessingDto(bool success, float diffStart, float diffEnd, int start, int bound, int end,
|
||||||
TimeSpan periodStart, TimeSpan periodEnd)
|
TimeSpan periodStart, TimeSpan periodEnd)
|
||||||
{
|
{
|
||||||
Success = success;
|
Success = success;
|
|
@ -1,12 +1,13 @@
|
||||||
using KLHZ.Trader.Core.Common.Messaging.Contracts.Messages;
|
using KLHZ.Trader.Core.Contracts.Declisions.Interfaces;
|
||||||
|
using KLHZ.Trader.Core.Contracts.Messaging.Dtos.Intarfaces;
|
||||||
|
|
||||||
namespace KLHZ.Trader.Core.Declisions.Models
|
namespace KLHZ.Trader.Core.Declisions.Services
|
||||||
{
|
{
|
||||||
public class PriceHistoryCacheUnit
|
public class PriceHistoryCacheUnit : IPriceHistoryCacheUnit
|
||||||
{
|
{
|
||||||
public const int ArrayMaxLength = 500;
|
public const int ArrayMaxLength = 500;
|
||||||
|
|
||||||
public readonly string Figi;
|
public string Figi { get; init; }
|
||||||
|
|
||||||
private readonly object _locker = new();
|
private readonly object _locker = new();
|
||||||
private readonly float[] Prices = new float[ArrayMaxLength];
|
private readonly float[] Prices = new float[ArrayMaxLength];
|
||||||
|
@ -14,7 +15,7 @@ namespace KLHZ.Trader.Core.Declisions.Models
|
||||||
|
|
||||||
private int Length = 0;
|
private int Length = 0;
|
||||||
|
|
||||||
public void AddData(INewPriceMessage priceChange)
|
public ValueTask AddData(INewPriceMessage priceChange)
|
||||||
{
|
{
|
||||||
lock (_locker)
|
lock (_locker)
|
||||||
{
|
{
|
||||||
|
@ -29,9 +30,10 @@ namespace KLHZ.Trader.Core.Declisions.Models
|
||||||
Length++;
|
Length++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return ValueTask.CompletedTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
public (DateTime[] timestamps, float[] prices) GetData()
|
public ValueTask<(DateTime[] timestamps, float[] prices)> GetData()
|
||||||
{
|
{
|
||||||
var prices = new float[Length];
|
var prices = new float[Length];
|
||||||
var timestamps = new DateTime[Length];
|
var timestamps = new DateTime[Length];
|
||||||
|
@ -39,7 +41,7 @@ namespace KLHZ.Trader.Core.Declisions.Models
|
||||||
{
|
{
|
||||||
Array.Copy(Prices, Prices.Length - Length, prices, 0, prices.Length);
|
Array.Copy(Prices, Prices.Length - Length, prices, 0, prices.Length);
|
||||||
Array.Copy(Timestamps, Prices.Length - Length, timestamps, 0, timestamps.Length);
|
Array.Copy(Timestamps, Prices.Length - Length, timestamps, 0, timestamps.Length);
|
||||||
return (timestamps, prices);
|
return ValueTask.FromResult((timestamps, prices));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
using KLHZ.Trader.Core.Common;
|
using KLHZ.Trader.Core.Common;
|
||||||
using KLHZ.Trader.Core.Common.Messaging.Contracts;
|
using KLHZ.Trader.Core.Contracts.Declisions.Interfaces;
|
||||||
using KLHZ.Trader.Core.Common.Messaging.Contracts.Messages;
|
using KLHZ.Trader.Core.Contracts.Messaging.Dtos.Enums;
|
||||||
using KLHZ.Trader.Core.Common.Messaging.Contracts.Messages.Enums;
|
using KLHZ.Trader.Core.Contracts.Messaging.Dtos.Intarfaces;
|
||||||
|
using KLHZ.Trader.Core.Contracts.Messaging.Interfaces;
|
||||||
using KLHZ.Trader.Core.DataLayer;
|
using KLHZ.Trader.Core.DataLayer;
|
||||||
using KLHZ.Trader.Core.DataLayer.Entities.Declisions;
|
using KLHZ.Trader.Core.DataLayer.Entities.Declisions;
|
||||||
using KLHZ.Trader.Core.Declisions.Models;
|
|
||||||
using KLHZ.Trader.Core.Declisions.Utils;
|
using KLHZ.Trader.Core.Declisions.Utils;
|
||||||
using KLHZ.Trader.Core.Exchange;
|
using KLHZ.Trader.Core.Exchange;
|
||||||
using KLHZ.Trader.Core.Exchange.Extentions;
|
using KLHZ.Trader.Core.Exchange.Extentions;
|
||||||
|
@ -30,6 +30,8 @@ namespace KLHZ.Trader.Core.Declisions.Services
|
||||||
private readonly IDbContextFactory<TraderDbContext> _dbContextFactory;
|
private readonly IDbContextFactory<TraderDbContext> _dbContextFactory;
|
||||||
private readonly ConcurrentDictionary<string, ManagedAccount> Accounts = new();
|
private readonly ConcurrentDictionary<string, ManagedAccount> Accounts = new();
|
||||||
private readonly ConcurrentDictionary<string, PriceHistoryCacheUnit> _historyCash = new();
|
private readonly ConcurrentDictionary<string, PriceHistoryCacheUnit> _historyCash = new();
|
||||||
|
private readonly ITradingEventsDetector _tradingEventsDetector;
|
||||||
|
|
||||||
|
|
||||||
private readonly decimal _futureComission;
|
private readonly decimal _futureComission;
|
||||||
private readonly decimal _shareComission;
|
private readonly decimal _shareComission;
|
||||||
|
@ -41,6 +43,7 @@ namespace KLHZ.Trader.Core.Declisions.Services
|
||||||
private readonly Channel<INewPriceMessage> _pricesChannel = Channel.CreateUnbounded<INewPriceMessage>();
|
private readonly Channel<INewPriceMessage> _pricesChannel = Channel.CreateUnbounded<INewPriceMessage>();
|
||||||
|
|
||||||
public Trader(
|
public Trader(
|
||||||
|
ITradingEventsDetector tradingEventsDetector,
|
||||||
BotModeSwitcher botModeSwitcher,
|
BotModeSwitcher botModeSwitcher,
|
||||||
IServiceProvider provider,
|
IServiceProvider provider,
|
||||||
IOptions<ExchangeConfig> options,
|
IOptions<ExchangeConfig> options,
|
||||||
|
@ -48,6 +51,7 @@ namespace KLHZ.Trader.Core.Declisions.Services
|
||||||
IDbContextFactory<TraderDbContext> dbContextFactory,
|
IDbContextFactory<TraderDbContext> dbContextFactory,
|
||||||
InvestApiClient investApiClient)
|
InvestApiClient investApiClient)
|
||||||
{
|
{
|
||||||
|
_tradingEventsDetector = tradingEventsDetector;
|
||||||
_botModeSwitcher = botModeSwitcher;
|
_botModeSwitcher = botModeSwitcher;
|
||||||
_dataBus = dataBus;
|
_dataBus = dataBus;
|
||||||
_provider = provider;
|
_provider = provider;
|
||||||
|
@ -100,59 +104,11 @@ namespace KLHZ.Trader.Core.Declisions.Services
|
||||||
data = new PriceHistoryCacheUnit(message.Figi, message);
|
data = new PriceHistoryCacheUnit(message.Figi, message);
|
||||||
_historyCash.TryAdd(message.Figi, data);
|
_historyCash.TryAdd(message.Figi, data);
|
||||||
}
|
}
|
||||||
|
var result = await _tradingEventsDetector.Detect(data);
|
||||||
float meanfullDiff;
|
|
||||||
if (message.Figi == "BBG004730N88")
|
|
||||||
{
|
|
||||||
meanfullDiff = 0.05f;
|
|
||||||
}
|
|
||||||
else if (message.Figi == "FUTIMOEXF000")
|
|
||||||
{
|
|
||||||
meanfullDiff = 1f;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
//var downtrendStarts = data.CheckDowntrendStarting(TimeSpan.FromSeconds(30), TimeSpan.FromSeconds(7), meanfullDiff);
|
if (result.LongOpen)
|
||||||
var uptrendStarts = data.CheckLongOpen(TimeSpan.FromSeconds(60), TimeSpan.FromSeconds(7), meanfullDiff, 8, 3);
|
|
||||||
var uptrendStarts2 = data.CheckLongOpen(TimeSpan.FromSeconds(60), TimeSpan.FromSeconds(3), meanfullDiff, 15, 2);
|
|
||||||
var downtrendEnds = data.CheckLongOpen(TimeSpan.FromSeconds(120), TimeSpan.FromSeconds(10), meanfullDiff, 15, 5);
|
|
||||||
uptrendStarts |= downtrendEnds;
|
|
||||||
uptrendStarts |= uptrendStarts2;
|
|
||||||
//var downtrendEnds = data.CheckDowntrendEnding(TimeSpan.FromSeconds(60), TimeSpan.FromSeconds(15), meanfullDiff);
|
|
||||||
|
|
||||||
var uptrendEnds = data.CheckLongClose(TimeSpan.FromSeconds(15), TimeSpan.FromSeconds(20), meanfullDiff * 1.5f, 8, 8);
|
|
||||||
var uptrendEnds2 = data.CheckLongClose(TimeSpan.FromSeconds(120), TimeSpan.FromSeconds(30), meanfullDiff, 15, 8);
|
|
||||||
uptrendEnds |= uptrendEnds2;
|
|
||||||
|
|
||||||
//var uptrendEnds2 = data.CheckUptrendEnding(TimeSpan.FromSeconds(20), TimeSpan.FromSeconds(20), meanfullDiff);
|
|
||||||
|
|
||||||
//var uptrendEnds = uptrendEnds1 || uptrendEnds2;
|
|
||||||
|
|
||||||
var declisionAction = DeclisionTradeAction.Unknown;
|
|
||||||
|
|
||||||
//if (downtrendStarts)
|
|
||||||
//{
|
|
||||||
// //declisionAction = DeclisionTradeAction.OpenShort;
|
|
||||||
//}
|
|
||||||
if (uptrendStarts)
|
|
||||||
{
|
|
||||||
declisionAction = DeclisionTradeAction.OpenLong;
|
|
||||||
}
|
|
||||||
//else if (downtrendEnds)
|
|
||||||
//{
|
|
||||||
// //declisionAction = DeclisionTradeAction.CloseShort;
|
|
||||||
//}
|
|
||||||
else if (uptrendEnds)
|
|
||||||
{
|
|
||||||
declisionAction = DeclisionTradeAction.CloseLong;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (declisionAction != DeclisionTradeAction.Unknown)
|
|
||||||
{
|
{
|
||||||
using var context = await _dbContextFactory.CreateDbContextAsync();
|
using var context = await _dbContextFactory.CreateDbContextAsync();
|
||||||
context.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking;
|
context.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking;
|
||||||
|
@ -163,7 +119,22 @@ namespace KLHZ.Trader.Core.Declisions.Services
|
||||||
Ticker = message.Ticker,
|
Ticker = message.Ticker,
|
||||||
Price = message.Value,
|
Price = message.Value,
|
||||||
Time = message.IsHistoricalData ? message.Time : DateTime.UtcNow,
|
Time = message.IsHistoricalData ? message.Time : DateTime.UtcNow,
|
||||||
Action = declisionAction,
|
Action = DeclisionTradeAction.OpenLong,
|
||||||
|
});
|
||||||
|
await context.SaveChangesAsync();
|
||||||
|
}
|
||||||
|
if (result.LongClose)
|
||||||
|
{
|
||||||
|
using var context = await _dbContextFactory.CreateDbContextAsync();
|
||||||
|
context.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking;
|
||||||
|
await context.Declisions.AddAsync(new Declision()
|
||||||
|
{
|
||||||
|
AccountId = string.Empty,
|
||||||
|
Figi = message.Figi,
|
||||||
|
Ticker = message.Ticker,
|
||||||
|
Price = message.Value,
|
||||||
|
Time = message.IsHistoricalData ? message.Time : DateTime.UtcNow,
|
||||||
|
Action = DeclisionTradeAction.CloseLong,
|
||||||
});
|
});
|
||||||
await context.SaveChangesAsync();
|
await context.SaveChangesAsync();
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,64 @@
|
||||||
|
using KLHZ.Trader.Core.Contracts.Declisions.Dtos;
|
||||||
|
using KLHZ.Trader.Core.Contracts.Declisions.Interfaces;
|
||||||
|
using KLHZ.Trader.Core.DataLayer.Entities.Declisions;
|
||||||
|
using KLHZ.Trader.Core.Declisions.Utils;
|
||||||
|
|
||||||
|
namespace KLHZ.Trader.Core.Declisions.Services
|
||||||
|
{
|
||||||
|
public class TradingEventsDetector : ITradingEventsDetector
|
||||||
|
{
|
||||||
|
public async ValueTask<TradingEventsDto> Detect(IPriceHistoryCacheUnit data)
|
||||||
|
{
|
||||||
|
await Task.Delay(0);
|
||||||
|
float meanfullDiff;
|
||||||
|
if (data.Figi == "BBG004730N88")
|
||||||
|
{
|
||||||
|
meanfullDiff = 0.05f;
|
||||||
|
}
|
||||||
|
else if (data.Figi == "FUTIMOEXF000")
|
||||||
|
{
|
||||||
|
meanfullDiff = 1f;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return TradingEventsDto.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
//var downtrendStarts = data.CheckDowntrendStarting(TimeSpan.FromSeconds(30), TimeSpan.FromSeconds(7), meanfullDiff);
|
||||||
|
var uptrendStarts = data.CheckLongOpen(TimeSpan.FromSeconds(60), TimeSpan.FromSeconds(7), meanfullDiff, 8, 3);
|
||||||
|
var uptrendStarts2 = data.CheckLongOpen(TimeSpan.FromSeconds(60), TimeSpan.FromSeconds(3), meanfullDiff, 15, 2);
|
||||||
|
var downtrendEnds = data.CheckLongOpen(TimeSpan.FromSeconds(120), TimeSpan.FromSeconds(10), meanfullDiff, 15, 5);
|
||||||
|
uptrendStarts |= downtrendEnds;
|
||||||
|
uptrendStarts |= uptrendStarts2;
|
||||||
|
//var downtrendEnds = data.CheckDowntrendEnding(TimeSpan.FromSeconds(60), TimeSpan.FromSeconds(15), meanfullDiff);
|
||||||
|
|
||||||
|
var uptrendEnds = data.CheckLongClose(TimeSpan.FromSeconds(15), TimeSpan.FromSeconds(20), meanfullDiff * 1.5f, 8, 8);
|
||||||
|
var uptrendEnds2 = data.CheckLongClose(TimeSpan.FromSeconds(120), TimeSpan.FromSeconds(30), meanfullDiff, 15, 8);
|
||||||
|
uptrendEnds |= uptrendEnds2;
|
||||||
|
|
||||||
|
//var uptrendEnds2 = data.CheckUptrendEnding(TimeSpan.FromSeconds(20), TimeSpan.FromSeconds(20), meanfullDiff);
|
||||||
|
|
||||||
|
//var uptrendEnds = uptrendEnds1 || uptrendEnds2;
|
||||||
|
|
||||||
|
var declisionAction = DeclisionTradeAction.Unknown;
|
||||||
|
|
||||||
|
//if (downtrendStarts)
|
||||||
|
//{
|
||||||
|
// //declisionAction = DeclisionTradeAction.OpenShort;
|
||||||
|
//}
|
||||||
|
if (uptrendStarts)
|
||||||
|
{
|
||||||
|
declisionAction = DeclisionTradeAction.OpenLong;
|
||||||
|
}
|
||||||
|
//else if (downtrendEnds)
|
||||||
|
//{
|
||||||
|
// //declisionAction = DeclisionTradeAction.CloseShort;
|
||||||
|
//}
|
||||||
|
else if (uptrendEnds)
|
||||||
|
{
|
||||||
|
declisionAction = DeclisionTradeAction.CloseLong;
|
||||||
|
}
|
||||||
|
return new TradingEventsDto(uptrendEnds, uptrendStarts);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,13 +1,15 @@
|
||||||
using KLHZ.Trader.Core.Declisions.Models;
|
using KLHZ.Trader.Core.Contracts.Declisions.Interfaces;
|
||||||
|
using KLHZ.Trader.Core.Declisions.Dtos;
|
||||||
|
using KLHZ.Trader.Core.Declisions.Services;
|
||||||
|
|
||||||
namespace KLHZ.Trader.Core.Declisions.Utils
|
namespace KLHZ.Trader.Core.Declisions.Utils
|
||||||
{
|
{
|
||||||
internal static class HistoryProcessingInstruments
|
internal static class HistoryProcessingInstruments
|
||||||
{
|
{
|
||||||
internal static PeriodPricesInfo GetPriceDiffForTimeSpan(this PriceHistoryCacheUnit unit, TimeSpan timeShift, TimeSpan timeSpan, int? pointsShift = null)
|
internal static PeriodPricesInfoDto GetPriceDiffForTimeSpan(this IPriceHistoryCacheUnit unit, TimeSpan timeShift, TimeSpan timeSpan, int? pointsShift = null)
|
||||||
{
|
{
|
||||||
var res = new PeriodPricesInfo(false, 0, 0, 0, 0, 0, timeSpan, 0, 0);
|
var res = new PeriodPricesInfoDto(false, 0, 0, 0, 0, 0, timeSpan, 0, 0);
|
||||||
var data = unit.GetData();
|
var data = unit.GetData().Result;
|
||||||
var times = data.timestamps;
|
var times = data.timestamps;
|
||||||
var prices = data.prices;
|
var prices = data.prices;
|
||||||
if (times.Length < 2) return res;
|
if (times.Length < 2) return res;
|
||||||
|
@ -47,7 +49,7 @@ namespace KLHZ.Trader.Core.Declisions.Utils
|
||||||
|
|
||||||
if (intervaStartIndex >= 0 && intervaEndIndex >= 0)
|
if (intervaStartIndex >= 0 && intervaEndIndex >= 0)
|
||||||
{
|
{
|
||||||
res = new PeriodPricesInfo(
|
res = new PeriodPricesInfoDto(
|
||||||
true,
|
true,
|
||||||
prices[intervaStartIndex],
|
prices[intervaStartIndex],
|
||||||
prices[intervaEndIndex],
|
prices[intervaEndIndex],
|
||||||
|
@ -62,31 +64,31 @@ namespace KLHZ.Trader.Core.Declisions.Utils
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static bool CheckStable(this PeriodPricesInfo data, float meanfullDiff)
|
internal static bool CheckStable(this PeriodPricesInfoDto data, float meanfullDiff)
|
||||||
{
|
{
|
||||||
meanfullDiff = Math.Abs(meanfullDiff);
|
meanfullDiff = Math.Abs(meanfullDiff);
|
||||||
return data.Success && Math.Abs(data.PeriodDiff) < 1.5 * meanfullDiff && Math.Abs(data.PeriodMax - data.PeriodMin) < 2 * meanfullDiff;
|
return data.Success && Math.Abs(data.PeriodDiff) < 1.5 * meanfullDiff && Math.Abs(data.PeriodMax - data.PeriodMin) < 2 * meanfullDiff;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static bool CheckGrowing(this PeriodPricesInfo data, float meanfullDiff)
|
internal static bool CheckGrowing(this PeriodPricesInfoDto data, float meanfullDiff)
|
||||||
{
|
{
|
||||||
return meanfullDiff > 0 && data.Success && data.PeriodDiff > meanfullDiff && Math.Abs(data.PeriodMax - data.PeriodMin) < 3 * Math.Abs(data.PeriodDiff);
|
return meanfullDiff > 0 && data.Success && data.PeriodDiff > meanfullDiff && Math.Abs(data.PeriodMax - data.PeriodMin) < 3 * Math.Abs(data.PeriodDiff);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static bool CheckFalling(this PeriodPricesInfo data, float meanfullDiff)
|
internal static bool CheckFalling(this PeriodPricesInfoDto data, float meanfullDiff)
|
||||||
{
|
{
|
||||||
meanfullDiff = -meanfullDiff;
|
meanfullDiff = -meanfullDiff;
|
||||||
return meanfullDiff < 0 && data.Success && data.PeriodDiff < meanfullDiff && Math.Abs(data.PeriodMax - data.PeriodMin) < 3 * Math.Abs(data.PeriodDiff);
|
return meanfullDiff < 0 && data.Success && data.PeriodDiff < meanfullDiff && Math.Abs(data.PeriodMax - data.PeriodMin) < 3 * Math.Abs(data.PeriodDiff);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static float CalcTrendRelationAbs(PeriodPricesInfo first, PeriodPricesInfo second)
|
internal static float CalcTrendRelationAbs(PeriodPricesInfoDto first, PeriodPricesInfoDto second)
|
||||||
{
|
{
|
||||||
var k1 = Math.Abs(first.PeriodDiff) / Math.Abs(first.Period.TotalSeconds);
|
var k1 = Math.Abs(first.PeriodDiff) / Math.Abs(first.Period.TotalSeconds);
|
||||||
var k2 = Math.Abs(second.PeriodDiff) / Math.Abs(second.Period.TotalSeconds);
|
var k2 = Math.Abs(second.PeriodDiff) / Math.Abs(second.Period.TotalSeconds);
|
||||||
if (k2 == 0 && k1 != 0) return 1000;
|
if (k2 == 0 && k1 != 0) return 1000;
|
||||||
return (float)(k1 / k2);
|
return (float)(k1 / k2);
|
||||||
}
|
}
|
||||||
internal static float CalcTrendRelationAbs(TwoPeriodsProcessingData data)
|
internal static float CalcTrendRelationAbs(TwoPeriodsProcessingDto data)
|
||||||
{
|
{
|
||||||
var k1 = Math.Abs(data.DiffStart) / Math.Abs(data.PeriodStart.TotalSeconds);
|
var k1 = Math.Abs(data.DiffStart) / Math.Abs(data.PeriodStart.TotalSeconds);
|
||||||
var k2 = Math.Abs(data.DiffEnd) / Math.Abs(data.PeriodEnd.TotalSeconds);
|
var k2 = Math.Abs(data.DiffEnd) / Math.Abs(data.PeriodEnd.TotalSeconds);
|
||||||
|
@ -94,7 +96,7 @@ namespace KLHZ.Trader.Core.Declisions.Utils
|
||||||
return (float)(k1 / k2);
|
return (float)(k1 / k2);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static bool CheckDowntrendEnding(this PriceHistoryCacheUnit unit, TimeSpan firstPeriod, TimeSpan secondPeriod, float meanfullDiff)
|
internal static bool CheckDowntrendEnding(this IPriceHistoryCacheUnit unit, TimeSpan firstPeriod, TimeSpan secondPeriod, float meanfullDiff)
|
||||||
{
|
{
|
||||||
var totalDiff = unit.GetPriceDiffForTimeSpan(TimeSpan.Zero, firstPeriod + secondPeriod);
|
var totalDiff = unit.GetPriceDiffForTimeSpan(TimeSpan.Zero, firstPeriod + secondPeriod);
|
||||||
var startDiff = unit.GetPriceDiffForTimeSpan(secondPeriod, firstPeriod);
|
var startDiff = unit.GetPriceDiffForTimeSpan(secondPeriod, firstPeriod);
|
||||||
|
@ -114,7 +116,7 @@ namespace KLHZ.Trader.Core.Declisions.Utils
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static bool CheckUptrendEnding(this PriceHistoryCacheUnit unit, TimeSpan firstPeriod, TimeSpan secondPeriod, float meanfullDiff)
|
internal static bool CheckUptrendEnding(this IPriceHistoryCacheUnit unit, TimeSpan firstPeriod, TimeSpan secondPeriod, float meanfullDiff)
|
||||||
{
|
{
|
||||||
var totalDiff = unit.GetPriceDiffForTimeSpan(TimeSpan.Zero, firstPeriod + secondPeriod);
|
var totalDiff = unit.GetPriceDiffForTimeSpan(TimeSpan.Zero, firstPeriod + secondPeriod);
|
||||||
var startDiff = unit.GetPriceDiffForTimeSpan(secondPeriod, firstPeriod);
|
var startDiff = unit.GetPriceDiffForTimeSpan(secondPeriod, firstPeriod);
|
||||||
|
@ -178,9 +180,9 @@ namespace KLHZ.Trader.Core.Declisions.Utils
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static TwoPeriodsProcessingData GetTwoPeriodsProcessingData(this (DateTime[] timestamps, float[] prices) data, TimeSpan shift, int shiftPointsStart, int shiftPointsEnd, TimeSpan firstPeriod, float meanfullDiff)
|
internal static TwoPeriodsProcessingDto GetTwoPeriodsProcessingData(this (DateTime[] timestamps, float[] prices) data, TimeSpan shift, int shiftPointsStart, int shiftPointsEnd, TimeSpan firstPeriod, float meanfullDiff)
|
||||||
{
|
{
|
||||||
var res = new TwoPeriodsProcessingData(success: false, 0, 0, 0, 0, 0, TimeSpan.Zero, TimeSpan.Zero);
|
var res = new TwoPeriodsProcessingDto(success: false, 0, 0, 0, 0, 0, TimeSpan.Zero, TimeSpan.Zero);
|
||||||
var time = data.timestamps;
|
var time = data.timestamps;
|
||||||
var prices = data.prices;
|
var prices = data.prices;
|
||||||
int count = -1;
|
int count = -1;
|
||||||
|
@ -210,14 +212,14 @@ namespace KLHZ.Trader.Core.Declisions.Utils
|
||||||
{
|
{
|
||||||
var diff1 = prices[bound] - prices[start];
|
var diff1 = prices[bound] - prices[start];
|
||||||
var diff2 = prices[end] - prices[bound];
|
var diff2 = prices[end] - prices[bound];
|
||||||
res = new TwoPeriodsProcessingData(true, diff1, diff2, start, bound, end, time[bound] - time[start], time[end] - time[bound]);
|
res = new TwoPeriodsProcessingDto(true, diff1, diff2, start, bound, end, time[bound] - time[start], time[end] - time[bound]);
|
||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static bool CheckLongClose(this PriceHistoryCacheUnit unit, TimeSpan firstPeriod, TimeSpan secondPeriod, float meanfullDiff, int pointsStart, int pointsEnd)
|
internal static bool CheckLongClose(this IPriceHistoryCacheUnit unit, TimeSpan firstPeriod, TimeSpan secondPeriod, float meanfullDiff, int pointsStart, int pointsEnd)
|
||||||
{
|
{
|
||||||
var data = unit.GetData();
|
var data = unit.GetData().Result;
|
||||||
var periodStat = data.GetTwoPeriodsProcessingData(secondPeriod, pointsStart, pointsEnd, firstPeriod, meanfullDiff);
|
var periodStat = data.GetTwoPeriodsProcessingData(secondPeriod, pointsStart, pointsEnd, firstPeriod, meanfullDiff);
|
||||||
var trendRelation = CalcTrendRelationAbs(periodStat);
|
var trendRelation = CalcTrendRelationAbs(periodStat);
|
||||||
var isStartOk = periodStat.Success && periodStat.DiffStart > 0 && periodStat.DiffStart > 1.5 * meanfullDiff;
|
var isStartOk = periodStat.Success && periodStat.DiffStart > 0 && periodStat.DiffStart > 1.5 * meanfullDiff;
|
||||||
|
@ -240,9 +242,9 @@ namespace KLHZ.Trader.Core.Declisions.Utils
|
||||||
return isStartOk && isEndOk && (data.prices[periodStat.End] - data.prices[periodStat.Start] >= meanfullDiff);
|
return isStartOk && isEndOk && (data.prices[periodStat.End] - data.prices[periodStat.Start] >= meanfullDiff);
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static bool CheckUptrendStarting2(this PriceHistoryCacheUnit unit, TimeSpan firstPeriod, TimeSpan secondPeriod, float meanfullDiff)
|
internal static bool CheckUptrendStarting2(this IPriceHistoryCacheUnit unit, TimeSpan firstPeriod, TimeSpan secondPeriod, float meanfullDiff)
|
||||||
{
|
{
|
||||||
var data = unit.GetData();
|
var data = unit.GetData().Result;
|
||||||
var periodStat = data.GetTwoPeriodsProcessingData(secondPeriod, 15, 2, firstPeriod, meanfullDiff);
|
var periodStat = data.GetTwoPeriodsProcessingData(secondPeriod, 15, 2, firstPeriod, meanfullDiff);
|
||||||
var trendRelation = CalcTrendRelationAbs(periodStat);
|
var trendRelation = CalcTrendRelationAbs(periodStat);
|
||||||
var isStartOk = periodStat.Success && periodStat.DiffStart < -meanfullDiff;
|
var isStartOk = periodStat.Success && periodStat.DiffStart < -meanfullDiff;
|
||||||
|
@ -265,9 +267,9 @@ namespace KLHZ.Trader.Core.Declisions.Utils
|
||||||
return isStartOk && isEndOk;
|
return isStartOk && isEndOk;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static bool _CheckUptrendStarting2(this PriceHistoryCacheUnit unit, TimeSpan firstPeriod, TimeSpan secondPeriod, float meanfullDiff)
|
internal static bool _CheckUptrendStarting2(this IPriceHistoryCacheUnit unit, TimeSpan firstPeriod, TimeSpan secondPeriod, float meanfullDiff)
|
||||||
{
|
{
|
||||||
var data = unit.GetData();
|
var data = unit.GetData().Result;
|
||||||
var periodStat = data.GetTwoPeriodsProcessingData(secondPeriod, 15, 1, firstPeriod, meanfullDiff);
|
var periodStat = data.GetTwoPeriodsProcessingData(secondPeriod, 15, 1, firstPeriod, meanfullDiff);
|
||||||
var trendRelation = CalcTrendRelationAbs(periodStat);
|
var trendRelation = CalcTrendRelationAbs(periodStat);
|
||||||
var isStartOk = periodStat.Success && periodStat.DiffStart < -meanfullDiff;
|
var isStartOk = periodStat.Success && periodStat.DiffStart < -meanfullDiff;
|
||||||
|
@ -291,9 +293,9 @@ namespace KLHZ.Trader.Core.Declisions.Utils
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
internal static bool CheckLongOpen(this PriceHistoryCacheUnit unit, TimeSpan firstPeriod, TimeSpan secondPeriod, float meanfullDiff, int pointsStart, int pointsEnd)
|
internal static bool CheckLongOpen(this IPriceHistoryCacheUnit unit, TimeSpan firstPeriod, TimeSpan secondPeriod, float meanfullDiff, int pointsStart, int pointsEnd)
|
||||||
{
|
{
|
||||||
var data = unit.GetData();
|
var data = unit.GetData().Result;
|
||||||
var periodStat = data.GetTwoPeriodsProcessingData(secondPeriod, pointsStart, pointsEnd, firstPeriod, meanfullDiff);
|
var periodStat = data.GetTwoPeriodsProcessingData(secondPeriod, pointsStart, pointsEnd, firstPeriod, meanfullDiff);
|
||||||
var trendRelation = CalcTrendRelationAbs(periodStat);
|
var trendRelation = CalcTrendRelationAbs(periodStat);
|
||||||
var isStartOk = periodStat.Success && periodStat.DiffStart < -meanfullDiff;
|
var isStartOk = periodStat.Success && periodStat.DiffStart < -meanfullDiff;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
using Grpc.Core;
|
using Grpc.Core;
|
||||||
using KLHZ.Trader.Core.Common.Messaging.Contracts;
|
using KLHZ.Trader.Core.Contracts.Messaging.Interfaces;
|
||||||
using KLHZ.Trader.Core.DataLayer;
|
using KLHZ.Trader.Core.DataLayer;
|
||||||
using KLHZ.Trader.Core.DataLayer.Entities.Prices;
|
using KLHZ.Trader.Core.DataLayer.Entities.Prices;
|
||||||
using KLHZ.Trader.Core.Exchange.Extentions;
|
using KLHZ.Trader.Core.Exchange.Extentions;
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
using KLHZ.Trader.Core.Common.Messaging.Contracts;
|
using KLHZ.Trader.Core.Contracts.Messaging.Dtos;
|
||||||
using KLHZ.Trader.Core.Common.Messaging.Contracts.Messages;
|
using KLHZ.Trader.Core.Contracts.Messaging.Dtos.Enums;
|
||||||
using KLHZ.Trader.Core.Common.Messaging.Contracts.Messages.Enums;
|
using KLHZ.Trader.Core.Contracts.Messaging.Interfaces;
|
||||||
using KLHZ.Trader.Core.DataLayer;
|
using KLHZ.Trader.Core.DataLayer;
|
||||||
using KLHZ.Trader.Core.Exchange.Extentions;
|
using KLHZ.Trader.Core.Exchange.Extentions;
|
||||||
using KLHZ.Trader.Core.Exchange.Models;
|
using KLHZ.Trader.Core.Exchange.Models;
|
||||||
|
|
|
@ -14,4 +14,8 @@
|
||||||
<PackageReference Include="Tinkoff.InvestApi" Version="0.6.17" />
|
<PackageReference Include="Tinkoff.InvestApi" Version="0.6.17" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\KLHZ.Trader.Core.Contracts\KLHZ.Trader.Core.Contracts.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
using KLHZ.Trader.Core.Common;
|
using KLHZ.Trader.Core.Common;
|
||||||
using KLHZ.Trader.Core.Common.Messaging.Contracts;
|
using KLHZ.Trader.Core.Contracts.Messaging.Dtos;
|
||||||
using KLHZ.Trader.Core.Common.Messaging.Contracts.Messages;
|
using KLHZ.Trader.Core.Contracts.Messaging.Dtos.Enums;
|
||||||
using KLHZ.Trader.Core.Common.Messaging.Contracts.Messages.Enums;
|
using KLHZ.Trader.Core.Contracts.Messaging.Interfaces;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
using System.Collections.Immutable;
|
using System.Collections.Immutable;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
using KLHZ.Trader.Core.Common.Messaging.Contracts;
|
using KLHZ.Trader.Core.Contracts.Messaging.Dtos.Intarfaces;
|
||||||
using KLHZ.Trader.Core.Common.Messaging.Contracts.Messages;
|
using KLHZ.Trader.Core.Contracts.Messaging.Interfaces;
|
||||||
using Microsoft.Extensions.Hosting;
|
using Microsoft.Extensions.Hosting;
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
using System.Collections.Immutable;
|
using System.Collections.Immutable;
|
||||||
|
@ -13,14 +13,14 @@ namespace KLHZ.Trader.Core.TG.Services
|
||||||
{
|
{
|
||||||
private readonly TelegramBotClient _botClient;
|
private readonly TelegramBotClient _botClient;
|
||||||
private readonly IUpdateHandler _updateHandler;
|
private readonly IUpdateHandler _updateHandler;
|
||||||
private readonly Channel<MessageForAdmin> _messages = Channel.CreateUnbounded<MessageForAdmin>();
|
private readonly Channel<IMessage> _messages = Channel.CreateUnbounded<IMessage>();
|
||||||
private readonly ImmutableArray<long> _admins = [];
|
private readonly ImmutableArray<long> _admins = [];
|
||||||
|
|
||||||
public BotStarter(IOptions<TgBotConfig> cfg, IUpdateHandler updateHandler, IDataBus dataBus, IOptions<TgBotConfig> options)
|
public BotStarter(IOptions<TgBotConfig> cfg, IUpdateHandler updateHandler, IDataBus dataBus, IOptions<TgBotConfig> options)
|
||||||
{
|
{
|
||||||
_botClient = new TelegramBotClient(cfg.Value.Token);
|
_botClient = new TelegramBotClient(cfg.Value.Token);
|
||||||
_updateHandler = updateHandler;
|
_updateHandler = updateHandler;
|
||||||
dataBus.AddChannel(_messages);
|
dataBus.AddChannel("", _messages);
|
||||||
_admins = ImmutableArray.CreateRange(options.Value.Admins);
|
_admins = ImmutableArray.CreateRange(options.Value.Admins);
|
||||||
_ = ProcessMessages();
|
_ = ProcessMessages();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
using KLHZ.Trader.Core.Common.Messaging.Contracts;
|
using KLHZ.Trader.Core.Contracts.Messaging.Dtos;
|
||||||
using KLHZ.Trader.Core.Common.Messaging.Contracts.Messages;
|
using KLHZ.Trader.Core.Contracts.Messaging.Interfaces;
|
||||||
using KLHZ.Trader.Core.DataLayer;
|
using KLHZ.Trader.Core.DataLayer;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
using KLHZ.Trader.Core.Common;
|
using KLHZ.Trader.Core.Common;
|
||||||
using KLHZ.Trader.Core.Common.Messaging.Contracts;
|
|
||||||
using KLHZ.Trader.Core.Common.Messaging.Services;
|
using KLHZ.Trader.Core.Common.Messaging.Services;
|
||||||
|
using KLHZ.Trader.Core.Contracts.Declisions.Interfaces;
|
||||||
|
using KLHZ.Trader.Core.Contracts.Messaging.Interfaces;
|
||||||
using KLHZ.Trader.Core.DataLayer;
|
using KLHZ.Trader.Core.DataLayer;
|
||||||
using KLHZ.Trader.Core.Declisions.Services;
|
using KLHZ.Trader.Core.Declisions.Services;
|
||||||
using KLHZ.Trader.Core.Exchange;
|
using KLHZ.Trader.Core.Exchange;
|
||||||
|
@ -49,6 +50,7 @@ builder.Services.AddHostedService<Trader>();
|
||||||
builder.Services.AddSingleton<IUpdateHandler, BotMessagesHandler>();
|
builder.Services.AddSingleton<IUpdateHandler, BotMessagesHandler>();
|
||||||
builder.Services.AddSingleton<BotModeSwitcher>();
|
builder.Services.AddSingleton<BotModeSwitcher>();
|
||||||
builder.Services.AddSingleton<IDataBus, DataBus>();
|
builder.Services.AddSingleton<IDataBus, DataBus>();
|
||||||
|
builder.Services.AddSingleton<ITradingEventsDetector, TradingEventsDetector>();
|
||||||
|
|
||||||
for (int i = 0; i < 10; i++)
|
for (int i = 0; i < 10; i++)
|
||||||
{
|
{
|
||||||
|
|
|
@ -40,6 +40,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "deploy", "deploy", "{9DE95D
|
||||||
build-docker-compose.yml = build-docker-compose.yml
|
build-docker-compose.yml = build-docker-compose.yml
|
||||||
EndProjectSection
|
EndProjectSection
|
||||||
EndProject
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "KLHZ.Trader.Core.Contracts", "KLHZ.Trader.Core.Contracts\KLHZ.Trader.Core.Contracts.csproj", "{C1ADC79B-ADDB-435D-A453-9D1623D144C4}"
|
||||||
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Any CPU = Debug|Any CPU
|
Debug|Any CPU = Debug|Any CPU
|
||||||
|
@ -66,6 +68,10 @@ Global
|
||||||
{9BF1E4ED-CCD5-401B-9F1C-3B7625258F7E}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{9BF1E4ED-CCD5-401B-9F1C-3B7625258F7E}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{9BF1E4ED-CCD5-401B-9F1C-3B7625258F7E}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{9BF1E4ED-CCD5-401B-9F1C-3B7625258F7E}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{9BF1E4ED-CCD5-401B-9F1C-3B7625258F7E}.Release|Any CPU.Build.0 = Release|Any CPU
|
{9BF1E4ED-CCD5-401B-9F1C-3B7625258F7E}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{C1ADC79B-ADDB-435D-A453-9D1623D144C4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{C1ADC79B-ADDB-435D-A453-9D1623D144C4}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{C1ADC79B-ADDB-435D-A453-9D1623D144C4}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{C1ADC79B-ADDB-435D-A453-9D1623D144C4}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
|
|
Loading…
Reference in New Issue