Чистка кода

dev
vlad zverzhkhovskiy 2025-10-07 12:26:25 +03:00
parent 50938f093e
commit 00de5bee2e
15 changed files with 157 additions and 1123 deletions

View File

@ -3,7 +3,7 @@
public class CachedValue
{
public DateTime Time { get; init; }
public decimal Value { get; init; }
public decimal Value2 { get; init; }
public decimal Count { get; init; }
public decimal Price { get; init; }
}
}

View File

@ -7,12 +7,12 @@ namespace KLHZ.Trader.Core.Math.Declisions.Utils
public static decimal Mean(this CachedValue[] values)
{
return values.Sum(x => x.Value) / values.Length;
return values.Sum(x => x.Count) / values.Length;
}
public static decimal Mean2(this CachedValue[] values)
{
return values.Sum(x => x.Value2) / values.Length;
return values.Sum(x => x.Price) / values.Length;
}
private static (decimal mean, decimal std) CaclSigma(decimal[] values)
@ -94,9 +94,9 @@ namespace KLHZ.Trader.Core.Math.Declisions.Utils
{
var tradevolume_diffMean = values.Mean();
var dprice_diffMean = values.Mean2();
var sum1 = (double)values.Sum(d => (d.Value - tradevolume_diffMean) * (d.Value2 - dprice_diffMean));
var sum2 = values.Sum(d => (d.Value - tradevolume_diffMean) * (d.Value - tradevolume_diffMean));
var sum3 = values.Sum(d => (d.Value2 - dprice_diffMean) * (d.Value2 - dprice_diffMean));
var sum1 = (double)values.Sum(d => (d.Count - tradevolume_diffMean) * (d.Price - dprice_diffMean));
var sum2 = values.Sum(d => (d.Count - tradevolume_diffMean) * (d.Count - tradevolume_diffMean));
var sum3 = values.Sum(d => (d.Price - dprice_diffMean) * (d.Price - dprice_diffMean));
if (sum2 != 0 && sum3 != 0)
{
result = (decimal)(sum1 / System.Math.Sqrt((double)(sum2 * sum3)));

View File

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

View File

@ -1,10 +0,0 @@
namespace KLHZ.Trader.Core.DataLayer.Entities.Trades.Enums
{
public enum AssetType
{
Unknown = 0,
Common = 1,
Future = 2,
Currency = 3,
}
}

View File

@ -1,9 +0,0 @@
namespace KLHZ.Trader.Core.DataLayer.Entities.Trades.Enums
{
public enum PositionType
{
Unknown = 0,
Long = 1,
Short = 2
}
}

View File

@ -1,52 +0,0 @@
using KLHZ.Trader.Core.DataLayer.Entities.Trades.Enums;
using System.ComponentModel.DataAnnotations.Schema;
namespace KLHZ.Trader.Core.DataLayer.Entities.Trades
{
/// <summary>
/// Сделка, совершенная ботом.
/// </summary>
[Table("trades")]
public class Trade
{
[Column("trade_id")]
public long Id { get; set; }
[Column("bought_at")]
public DateTime BoughtAt { get; set; }
[Column("account_id")]
public required string AccountId { get; set; }
[Column("figi")]
public required string Figi { get; set; }
[Column("ticker")]
public required string Ticker { get; set; }
[Column("price")]
public decimal Price { get; set; }
[Column("count")]
public decimal Count { get; set; }
[Column("count_lots")]
public decimal CountLots { get; set; }
[Column("archive_status")]
public int ArchiveStatus { get; set; }
[Column("direction")]
public TradeDirection Direction { get; set; }
[Column("position_type")]
public PositionType Position { get; set; }
[Column("asset_type")]
public AssetType Asset { get; set; }
[Column("asset_id")]
public Guid AssetId { get; set; }
}
}

View File

@ -1,7 +1,6 @@
using KLHZ.Trader.Core.DataLayer.Entities.Declisions;
using KLHZ.Trader.Core.DataLayer.Entities.Orders;
using KLHZ.Trader.Core.DataLayer.Entities.Prices;
using KLHZ.Trader.Core.DataLayer.Entities.Trades;
using Microsoft.EntityFrameworkCore;
@ -9,7 +8,6 @@ namespace KLHZ.Trader.Core.DataLayer
{
public class TraderDbContext : DbContext
{
public DbSet<Trade> Trades { get; set; }
public DbSet<Declision> Declisions { get; set; }
public DbSet<PriceChange> PriceChanges { get; set; }
public DbSet<ProcessedPrice> ProcessedPrices { get; set; }
@ -23,15 +21,6 @@ namespace KLHZ.Trader.Core.DataLayer
{
modelBuilder.UseSerialColumns();
modelBuilder.Entity<Trade>(entity =>
{
entity.HasKey(e1 => e1.Id);
entity.Property(e => e.BoughtAt)
.HasConversion(
v => v.ToUniversalTime(),
v => DateTime.SpecifyKind(v, DateTimeKind.Utc));
});
modelBuilder.Entity<Declision>(entity =>
{
entity.HasKey(e1 => e1.Id);

View File

@ -1,12 +0,0 @@
namespace KLHZ.Trader.Core.Exchange.Models.AssetsAccounting
{
public class DealResult
{
public required string AccountId { get; set; }
public required string Figi { get; set; }
public decimal Price { get; set; }
public decimal Count { get; set; }
public bool Success { get; set; }
public DealDirection Direction { get; set; }
}
}

View File

@ -1,15 +0,0 @@
namespace KLHZ.Trader.Core.Exchange.Models.AssetsAccounting
{
public class Order
{
public required string AccountId { get; init; }
public required string Figi { get; init; }
public required string Ticker { get; init; }
public required string OrderId { get; init; }
public decimal Price { get; init; }
public long Count { get; init; }
public DateTime ExpirationTime { get; init; }
public DateTime OpenDate { get; init; }
public DealDirection Direction { get; init; }
}
}

View File

@ -2,16 +2,16 @@
{
public class ExchangeConfig
{
public bool ExchangeDataRecievingEnabled { get; set; }
public decimal StopBuyLengthMinuts { get; set; }
public decimal FutureComission { get; set; }
public decimal ShareComission { get; set; }
public decimal AccountCashPart { get; set; }
public decimal AccountCashPartFutures { get; set; }
public decimal DefaultBuyPartOfAccount { get; set; }
public string[] DataRecievingInstrumentsFigis { get; set; } = [];
public string[] TradingInstrumentsFigis { get; set; } = [];
public string[] ManagingAccountNamePatterns { get; set; } = [];
public InstrumentSettings[] InstrumentsSettings { get; set; } = [];
public bool ExchangeDataRecievingEnabled { get; init; }
public decimal StopBuyLengthMinuts { get; init; }
public decimal FutureComission { get; init; }
public decimal ShareComission { get; init; }
public decimal AccountCashPart { get; init; }
public decimal AccountCashPartFutures { get; init; }
public decimal DefaultBuyPartOfAccount { get; init; }
public string[] DataRecievingInstrumentsFigis { get; init; } = [];
public string[] TradingInstrumentsFigis { get; init; } = [];
public string[] ManagingAccountNamePatterns { get; init; } = [];
public InstrumentSettings[] InstrumentsSettings { get; init; } = [];
}
}

View File

@ -6,7 +6,6 @@ using KLHZ.Trader.Core.DataLayer.Entities.Orders;
using KLHZ.Trader.Core.DataLayer.Entities.Prices;
using KLHZ.Trader.Core.Exchange.Extentions;
using KLHZ.Trader.Core.Exchange.Models.Configs;
using KLHZ.Trader.Core.Exchange.Utils;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
@ -156,39 +155,7 @@ namespace KLHZ.Trader.Core.Exchange.Services
Count = response.Trade.Quantity,
};
//await _tradeDataProvider.AddData(message, TimeSpan.FromHours(7));
await _eventBus.Broadcast(message);
var exchangeState = ExchangeScheduler.GetCurrentState();
if (exchangeState == Models.Trading.ExchangeState.ClearingTime
&& lastUpdateDict.TryGetValue(message.Figi, out var pri)
&& (DateTime.UtcNow - pri.Time).Minutes > 3)
{
var assets = _portfolioWrapper.Accounts.Values.SelectMany(a => a.Assets.Values).Where(a => a.Figi == message.Figi).ToArray();
foreach (var a in assets)
{
using var context = await _dbContextFactory.CreateDbContextAsync();
context.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking;
await context.Trades.AddAsync(new DataLayer.Entities.Trades.Trade()
{
AssetId = a.AssetId,
AccountId = string.Empty,
Figi = message.Figi,
Ticker = string.Empty,
ArchiveStatus = 0,
Asset = (KLHZ.Trader.Core.DataLayer.Entities.Trades.Enums.AssetType)(int)a.Type,
BoughtAt = DateTime.UtcNow,
Count = 0,
Direction = a.Count > 0 ? DataLayer.Entities.Trades.Enums.TradeDirection.Buy : DataLayer.Entities.Trades.Enums.TradeDirection.Sell,
Position = a.Count > 0 ? DataLayer.Entities.Trades.Enums.PositionType.Long : DataLayer.Entities.Trades.Enums.PositionType.Short,
Price = message.Value,
});
await context.SaveChangesAsync();
}
}
lastUpdateDict[message.Figi] = message;
pricesBuffer.Add(message);
}
if (response.Orderbook != null)

View File

@ -50,13 +50,11 @@ namespace KLHZ.Trader.Core.Exchange.Services
public ImmutableDictionary<string, Asset> Assets => GetAssets();
private readonly InvestApiClient _investApiClient;
private readonly IDbContextFactory<TraderDbContext> _dbContextFactory;
private readonly ILogger<TraderDataProvider> _logger;
private readonly IOptions<ExchangeConfig> _options;
private readonly Dictionary<string, Asset> _assets = new();
private readonly ConcurrentDictionary<string, DateTime> _usedOrderIds = new();
@ -140,26 +138,20 @@ namespace KLHZ.Trader.Core.Exchange.Services
using var context = await _dbContextFactory.CreateDbContextAsync();
context.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking;
var trades = await context.Trades
.Where(t => t.ArchiveStatus == 0)
.OrderByDescending(t => t.BoughtAt)
.ToListAsync();
var oldAssets = _assets.ToDictionary();
_assets.Clear();
foreach (var position in portfolio.Positions)
{
oldAssets.TryGetValue(position.Figi, out var oldAsset);
var newAssetId = oldAsset?.AssetId ?? Guid.NewGuid();
var trade = trades.FirstOrDefault(t => t.Figi == position.Figi && t.AssetId == newAssetId);
var asset = new Asset()
{
AssetId = newAssetId,
AccountId = AccountId,
Figi = position.Figi,
Ticker = position.Ticker,
BoughtAt = trade?.BoughtAt ?? DateTime.UtcNow,
BoughtPrice = trade?.Price ?? position.AveragePositionPrice,
BoughtAt = oldAsset?.BoughtAt ?? DateTime.UtcNow,
BoughtPrice = oldAsset?.BoughtPrice ?? position.AveragePositionPrice,
Type = position.InstrumentType.ParseInstrumentType(),
Position = position.Quantity > 0 ? PositionType.Long : PositionType.Short,
BlockedItems = position.BlockedLots,

File diff suppressed because it is too large Load Diff

View File

@ -257,7 +257,7 @@ namespace KLHZ.Trader.Core.Exchange.Services
{
if (ShapeAreaCalculator.TryGetAreasRelation(cachedData.timestamps, cachedData.prices, price.Value, Constants.AreasRelationWindow, out var rel))
{
await AddDataTo1MinuteWindowCache(price.Figi, Constants._1minCacheKey, new CachedValue() { Time = price.Time, Value = (decimal)rel });
await AddDataTo1MinuteWindowCache(price.Figi, Constants._1minCacheKey, new CachedValue() { Time = price.Time, Count = (decimal)rel });
}
}
}

View File

@ -0,0 +1,93 @@
using KLHZ.Trader.Core.Common;
using KLHZ.Trader.Core.Contracts.Declisions.Dtos.Enums;
using KLHZ.Trader.Core.Contracts.Messaging.Dtos.Interfaces;
using KLHZ.Trader.Core.DataLayer.Entities.Prices;
using KLHZ.Trader.Core.Exchange.Interfaces;
using KLHZ.Trader.Core.Exchange.Models.AssetsAccounting;
using System.Collections.Immutable;
namespace KLHZ.Trader.Core.Exchange.Utils
{
internal static class TraderUtils
{
internal static Dictionary<TradingEvent, decimal> MergeResultsMult(Dictionary<TradingEvent, decimal> res, ImmutableDictionary<TradingEvent, decimal> data)
{
foreach (var k in res.Keys)
{
var valRes = res[k];
var valData = data[k];
res[k] = valRes * valData;
}
return res;
}
internal static Dictionary<TradingEvent, decimal> MergeResultsMax(Dictionary<TradingEvent, decimal> res, ImmutableDictionary<TradingEvent, decimal> data)
{
foreach (var k in res.Keys)
{
var valRes = res[k];
var valData = data[k];
res[k] = System.Math.Max(valRes, valData);
}
return res;
}
internal static Dictionary<TradingEvent, decimal> GetInitDict(decimal initValue)
{
var values = System.Enum.GetValues<TradingEvent>();
return values.ToDictionary(v => v, v => initValue);
}
internal static bool IsOperationAllowed(IManagedAccount account, decimal boutPrice, decimal count,
decimal accountCashPartFutures, decimal accountCashPart)
{
if (!BotModeSwitcher.CanPurchase()) return false;
var balance = account.Balance;
var total = account.Total;
var futures = account.Assets.Values.FirstOrDefault(v => v.Type == AssetType.Futures);
if (futures != null)
{
if ((balance - boutPrice * count) / total < accountCashPartFutures) return false;
}
else
{
if ((balance - boutPrice * count) / total < accountCashPart) return false;
}
return true;
}
internal static INewPrice FilterHighFreqValues(INewPrice message, Dictionary<string, List<INewPrice>> pricesCache1)
{
if (!pricesCache1.TryGetValue(message.Figi, out var list))
{
list = new List<INewPrice>();
pricesCache1[message.Figi] = list;
}
list.Add(message);
if ((list.Last().Time - list.First().Time).TotalSeconds < 0.5)
{
list.Add(message);
return message;
}
else
{
message = new PriceChange()
{
Figi = message.Figi,
Ticker = message.Ticker,
Count = list.Sum(l => l.Count),
Direction = message.Direction,
IsHistoricalData = message.IsHistoricalData,
Time = message.Time,
Value = list.Sum(l => l.Value) / list.Count
};
list.Clear();
return message;
}
}
}
}