Унификация используемых моделей

dev
vlad zverzhkhovskiy 2025-10-07 13:38:49 +03:00
parent 41d33356dd
commit 584e378990
19 changed files with 16 additions and 288 deletions

View File

@ -1,4 +1,4 @@
namespace KLHZ.Trader.Core.Exchange.Models.AssetsAccounting
namespace KLHZ.Trader.Core.Contracts.Common.Enums
{
public enum PositionType
{

View File

@ -1,4 +1,4 @@
namespace KLHZ.Trader.Core.Common
namespace KLHZ.Trader.Core.Contracts.Common.Enums
{
public enum TradeDirection
{

View File

@ -1,6 +1,6 @@
namespace KLHZ.Trader.Core.Contracts.Declisions.Dtos
{
public class CachedValue //: ICachedValue
public class CachedValue
{
public DateTime Time { get; init; }
public long Count { get; init; }

View File

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

View File

@ -1,9 +0,0 @@
namespace KLHZ.Trader.Core.Contracts.Messaging.Dtos.Interfaces
{
public interface ILockableObject
{
public Task<bool> Lock(TimeSpan duration);
public void Unlock();
}
}

View File

@ -1,15 +0,0 @@
namespace KLHZ.Trader.Core.Contracts.Messaging.Dtos.Interfaces
{
public interface INewCandle
{
public bool IsHistoricalData { get; set; }
public decimal Open { get; set; }
public decimal Close { get; set; }
public decimal High { get; set; }
public decimal Low { get; set; }
public decimal Volume { get; set; }
public string Figi { get; set; }
public string Ticker { get; set; }
public DateTime Time { get; set; }
}
}

View File

@ -12,6 +12,5 @@ namespace KLHZ.Trader.Core.Contracts.Messaging.Dtos.Interfaces
public string AccountId { get; }
public string? OrderId { get; }
public bool EnableMargin { get; }
public ILockableObject? ExchangeObject { get; }
}
}

View File

@ -12,7 +12,6 @@ namespace KLHZ.Trader.Core.Contracts.Messaging.Dtos
public long Count { get; init; }
public required string AccountId { get; init; }
public bool EnableMargin { get; init; } = true;
public ILockableObject? ExchangeObject { get; init; }
public string? OrderId { get; init; }
}
}

View File

@ -2,7 +2,7 @@
namespace KLHZ.Trader.Core.Contracts.Messaging.Dtos
{
public class NewTrade : ITradeDataItem
public class TradeDataItem : ITradeDataItem
{
public decimal Price { get; set; }
public required string Figi { get; set; }

View File

@ -1,224 +0,0 @@
using KLHZ.Trader.Core.Contracts.Declisions.Dtos;
using KLHZ.Trader.Core.Contracts.Declisions.Dtos.Enums;
using KLHZ.Trader.Core.Contracts.Declisions.Interfaces;
using KLHZ.Trader.Core.Contracts.Messaging.Dtos.Interfaces;
using KLHZ.Trader.Core.Math.Declisions.Dtos;
using System.Collections.Concurrent;
namespace KLHZ.Trader.Core.Math.Declisions.Services.Cache
{
public class PriceHistoryCacheUnit3 : IPriceHistoryCacheUnit
{
public const int CacheMaxLength = 30000;
private const int _arrayMaxLength = 60000;
public string Figi { get; init; }
public int Length
{
get
{
lock (_locker)
{
return _length;
}
}
}
public decimal AsksCount
{
get
{
lock (_locker)
{
return _asksCount;
}
}
}
public decimal BidsCount
{
get
{
lock (_locker)
{
return _bidsCount;
}
}
}
private readonly object _locker = new();
private readonly decimal[] Prices = new decimal[_arrayMaxLength];
private readonly DateTime[] Timestamps = new DateTime[_arrayMaxLength];
private readonly ConcurrentDictionary<string, TimeWindowCacheItem> _20_secTimeWindows = new();
private readonly ConcurrentDictionary<string, TimeWindowCacheItem> _1_minTimeWindows = new();
private readonly ConcurrentDictionary<string, TimeWindowCacheItem> _5_minTimeWindows = new();
private readonly ConcurrentDictionary<string, TimeWindowCacheItem> _15_minTimeWindows = new();
private int _length = 0;
private int _pointer = -1;
private long _asksCount = 1;
private long _bidsCount = 1;
public ValueTask AddDataToTimeWindowCache(string key, CachedValue data, TimeWindowCacheType timeWindowCacheType)
{
var dict = GetDict(timeWindowCacheType);
if (!dict.TryGetValue(key, out var cahcheItem))
{
dict.TryAdd(key, new TimeWindowCacheItem(key, timeWindowCacheType));
}
dict[key].AddData(data);
return ValueTask.CompletedTask;
}
public ValueTask<CachedValue[]> GetDataFromTimeWindowCache(string key, TimeWindowCacheType timeWindowCacheType)
{
var dict = GetDict(timeWindowCacheType);
if (dict.TryGetValue(key, out var cahcheItem))
{
return cahcheItem.GetValues();
}
return ValueTask.FromResult(Array.Empty<CachedValue>());
}
private ConcurrentDictionary<string, TimeWindowCacheItem> GetDict(TimeWindowCacheType timeWindowCacheType)
{
switch (timeWindowCacheType)
{
case TimeWindowCacheType._5_Minutes:
{
return _5_minTimeWindows;
}
case TimeWindowCacheType._15_Minutes:
{
return _15_minTimeWindows;
}
case TimeWindowCacheType._20_Seconds:
{
return _20_secTimeWindows;
}
default:
{
return _1_minTimeWindows; ;
}
}
}
public ValueTask AddData(ITradeDataItem priceChange)
{
if (priceChange.Figi != Figi) return ValueTask.CompletedTask;
lock (_locker)
{
_pointer++;
Prices[_pointer] = priceChange.Price;
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, decimal[] prices)> GetData(int? length = null)
{
lock (_locker)
{
if (_pointer < 0)
{
return ValueTask.FromResult((Array.Empty<DateTime>(), Array.Empty<decimal>()));
}
else
{
var dataLength = length.HasValue ? System.Math.Min(length.Value, _length) : _length;
var prices = new decimal[dataLength];
var timestamps = new DateTime[dataLength];
var index = 1 + _pointer - dataLength;
Array.Copy(Prices, index, prices, 0, prices.Length);
Array.Copy(Timestamps, index, timestamps, 0, timestamps.Length);
return ValueTask.FromResult((timestamps, prices));
}
}
}
public ValueTask AddOrderbook(IOrderbook orderbook)
{
if (orderbook.Figi != Figi) return ValueTask.CompletedTask;
lock (_locker)
{
_asksCount = orderbook.AsksCount;
_bidsCount = orderbook.BidsCount;
}
return ValueTask.CompletedTask;
}
public ValueTask<(DateTime time, decimal price)> GetLastValues()
{
lock (_locker)
{
return _pointer >= 0 ? ValueTask.FromResult((Timestamps[_pointer], Prices[_pointer])) : ValueTask.FromResult((DateTime.UtcNow, 0m));
}
}
public ValueTask<(DateTime[] timestamps, decimal[] prices, bool isFullIntervalExists)> GetData(TimeSpan period)
{
lock (_locker)
{
if (_pointer < 0)
{
return ValueTask.FromResult((Array.Empty<DateTime>(), Array.Empty<decimal>(), false));
}
else
{
var i = _pointer;
var lastTime = Timestamps[i];
for (i = _pointer - 1; i >= 0; i--)
{
var currentTime = Timestamps[i];
if (lastTime - currentTime >= period)
{
break;
}
}
var dataLength = _pointer - i;
var prices = new decimal[dataLength];
var timestamps = new DateTime[dataLength];
var index = 1 + _pointer - dataLength;
Array.Copy(Prices, index, prices, 0, prices.Length);
Array.Copy(Timestamps, index, timestamps, 0, timestamps.Length);
return ValueTask.FromResult((timestamps, prices, i + 1 != 0));
}
}
}
public PriceHistoryCacheUnit3(string figi, params ITradeDataItem[] 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).AsTask().Wait();
}
}
}
}

View File

@ -5,10 +5,5 @@
Unknown = 0,
Ask = 1,
Bid = 2,
AsksSummary10 = 3,
BidsSummary10 = 4,
AsksSummary4 = 5,
BidsSummary4 = 6,
BidsAsksSummary4_2min = 7,
}
}

View File

@ -1,4 +1,5 @@
using KLHZ.Trader.Core.Exchange.Models.AssetsAccounting;
using KLHZ.Trader.Core.Contracts.Common.Enums;
using KLHZ.Trader.Core.Exchange.Models.AssetsAccounting;
using System.Collections.Immutable;
namespace KLHZ.Trader.Core.Exchange.Interfaces

View File

@ -1,4 +1,6 @@
namespace KLHZ.Trader.Core.Exchange.Models.AssetsAccounting
using KLHZ.Trader.Core.Contracts.Common.Enums;
namespace KLHZ.Trader.Core.Exchange.Models.AssetsAccounting
{
public class Asset
{

View File

@ -1,9 +0,0 @@
namespace KLHZ.Trader.Core.Exchange.Models.AssetsAccounting
{
public enum DealDirection
{
Unknown = 0,
Buy = 1,
Sell = 2
}
}

View File

@ -1,8 +1,8 @@
using KLHZ.Trader.Core.Common.Extentions;
using KLHZ.Trader.Core.Contracts.Common.Enums;
using KLHZ.Trader.Core.DataLayer;
using KLHZ.Trader.Core.Exchange.Extentions;
using KLHZ.Trader.Core.Exchange.Interfaces;
using KLHZ.Trader.Core.Exchange.Models.AssetsAccounting;
using KLHZ.Trader.Core.Exchange.Models.Configs;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;

View File

@ -1,4 +1,5 @@
using KLHZ.Trader.Core.Common;
using KLHZ.Trader.Core.Contracts.Common.Enums;
using KLHZ.Trader.Core.Contracts.Declisions.Dtos.Enums;
using KLHZ.Trader.Core.Contracts.Messaging.Dtos;
using KLHZ.Trader.Core.Contracts.Messaging.Dtos.Enums;
@ -6,6 +7,7 @@ using KLHZ.Trader.Core.Contracts.Messaging.Dtos.Interfaces;
using KLHZ.Trader.Core.Contracts.Messaging.Interfaces;
using KLHZ.Trader.Core.DataLayer.Entities.Declisions.Enums;
using KLHZ.Trader.Core.Exchange.Interfaces;
using KLHZ.Trader.Core.Exchange.Models.AssetsAccounting;
using KLHZ.Trader.Core.Exchange.Models.Configs;
using KLHZ.Trader.Core.Exchange.Models.Trading;
using KLHZ.Trader.Core.Exchange.Utils;
@ -19,9 +21,6 @@ using System.Collections.Immutable;
using System.Security.Cryptography;
using System.Threading.Channels;
using Tinkoff.InvestApi;
using Asset = KLHZ.Trader.Core.Exchange.Models.AssetsAccounting.Asset;
using AssetType = KLHZ.Trader.Core.Exchange.Models.AssetsAccounting.AssetType;
using PositionType = KLHZ.Trader.Core.Exchange.Models.AssetsAccounting.PositionType;
namespace KLHZ.Trader.Core.Exchange.Services
{
@ -80,7 +79,7 @@ namespace KLHZ.Trader.Core.Exchange.Services
if (command.CommandType == TradeCommandType.OpenLong
|| command.CommandType == TradeCommandType.OpenShort)
{
var fakeMessage = new NewTrade() { Figi = command.Figi, Ticker = "", Count = command.Count, Direction = 1, IsHistoricalData = false, Time = DateTime.UtcNow, Price = command.RecomendPrice ?? 0m };
var fakeMessage = new TradeDataItem() { Figi = command.Figi, Ticker = "", Count = command.Count, Direction = 1, IsHistoricalData = false, Time = DateTime.UtcNow, Price = command.RecomendPrice ?? 0m };
var positionType = command.CommandType == TradeCommandType.OpenLong ? PositionType.Long : PositionType.Short;
var stops = GetStops(fakeMessage, positionType);
var accounts = _portfolioWrapper.Accounts
@ -92,7 +91,7 @@ namespace KLHZ.Trader.Core.Exchange.Services
}
else
{
var fakeMessage = new NewTrade() { Figi = command.Figi, Ticker = "", Count = command.Count, Direction = 1, IsHistoricalData = false, Time = DateTime.UtcNow, Price = command.RecomendPrice ?? 0m };
var fakeMessage = new TradeDataItem() { Figi = command.Figi, Ticker = "", Count = command.Count, Direction = 1, IsHistoricalData = false, Time = DateTime.UtcNow, Price = command.RecomendPrice ?? 0m };
var assetsForClose = _portfolioWrapper.Accounts
.SelectMany(a => a.Value.Assets.Values)
.Where(a => a.Figi == fakeMessage.Figi)

View File

@ -236,7 +236,7 @@ namespace KLHZ.Trader.Core.Exchange.Services
var data = await context1.PriceChanges
.Where(c => _instrumentsFigis.Contains(c.Figi) && c.Time >= time)
.OrderBy(c => c.Time)
.Select(c => new NewTrade()
.Select(c => new TradeDataItem()
{
Figi = c.Figi,
Ticker = c.Ticker,

View File

@ -49,7 +49,7 @@ namespace KLHZ.Trader.Service.Controllers
var prices = await context1.PriceChanges
.Where(c => (c.Figi == figi1 || c.Figi == figi2) && c.Time >= time1 && c.Time < time2)
.OrderBy(c => c.Time)
.Select(c => new NewTrade()
.Select(c => new TradeDataItem()
{
Figi = c.Figi,
Ticker = c.Ticker,