переход на секционированную таблицу
test / deploy_trader_prod (push) Successful in 5m43s Details

main
vlad zverzhkhovskiy 2025-10-20 15:36:39 +03:00
parent ecd9a70e2e
commit 61b98e88f7
7 changed files with 225 additions and 58 deletions

View File

@ -0,0 +1,45 @@
using KLHZ.Trader.Core.Contracts.Messaging.Dtos;
using KLHZ.Trader.Core.Contracts.Messaging.Dtos.Interfaces;
using System.ComponentModel.DataAnnotations.Schema;
namespace KLHZ.Trader.Core.DataLayer.Entities.Prices
{
[Table("experiment_results")]
public class ExperimentsResult : IProcessedPrice
{
[Column("id")]
public long Id { get; set; }
[Column("time")]
public DateTime Time { get; set; }
[Column("value")]
public decimal Price { get; set; }
[Column("figi")]
public required string Figi { get; set; }
[Column("ticker")]
public required string Ticker { get; set; }
public bool IsHistoricalData { get; set; }
[Column("processor")]
public required string Processor { get; set; }
[NotMapped]
public long Count { get; set; }
[NotMapped]
public int Direction { get; set; }
[NotMapped]
public decimal Value { get; set; }
[NotMapped]
public decimal Value2 { get; set; }
[NotMapped]
public AttachedInfo? AttachedInfo { get; private set; }
}
}

View File

@ -0,0 +1,32 @@
using KLHZ.Trader.Core.Contracts.Messaging.Dtos.Interfaces;
using KLHZ.Trader.Core.DataLayer.Entities.Orders.Enums;
using System.ComponentModel.DataAnnotations.Schema;
namespace KLHZ.Trader.Core.DataLayer.Entities.Orders
{
[Table("orderbook_elements")]
public class OrderbookElement : IOrderbookItem
{
[Column("id")]
public long Id { get; set; }
[Column("time")]
public DateTime Time { get; set; }
[Column("price")]
public decimal Price { get; set; }
[Column("count")]
public long Count { get; set; }
[Column("figi")]
public required string Figi { get; set; }
[Column("ticker")]
public required string Ticker { get; set; }
[Column("item_type")]
public OrderbookItemType ItemType { get; set; }
}
}

View File

@ -1,62 +1,10 @@
using KLHZ.Trader.Core.Contracts.Messaging.Dtos;
using KLHZ.Trader.Core.Contracts.Messaging.Dtos.Interfaces;
using System.ComponentModel.DataAnnotations.Schema;
using System.ComponentModel.DataAnnotations.Schema;
namespace KLHZ.Trader.Core.DataLayer.Entities.Prices
{
[Table("price_changes")]
public class PriceChange : ITradeDataItem
public class PriceChange : Trade
{
[Column("id")]
public long Id { get; set; }
[Column("time")]
public DateTime Time { get; set; }
[Column("value")]
public decimal Price { get; set; }
[Column("figi")]
public required string Figi { get; set; }
[Column("ticker")]
public required string Ticker { get; set; }
[NotMapped]
public bool IsHistoricalData { get; set; }
[Column("count")]
public long Count { get; set; }
[Column("direction")]
public int Direction { get; set; }
[NotMapped]
public decimal Value { get; set; }
[NotMapped]
public decimal Value2 { get; set; }
[NotMapped]
public AttachedInfo? AttachedInfo
{
get
{
lock (_locker)
{
return _attachedInfo;
}
}
}
public void SetAttachedInfo(AttachedInfo? attachedInfo)
{
lock (_locker)
{
_attachedInfo = attachedInfo;
}
}
private AttachedInfo? _attachedInfo;
private readonly object _locker = new();
}
}

View File

@ -0,0 +1,62 @@
using KLHZ.Trader.Core.Contracts.Messaging.Dtos;
using KLHZ.Trader.Core.Contracts.Messaging.Dtos.Interfaces;
using System.ComponentModel.DataAnnotations.Schema;
namespace KLHZ.Trader.Core.DataLayer.Entities.Prices
{
[Table("trades")]
public class Trade : ITradeDataItem
{
[Column("id")]
public long Id { get; set; }
[Column("time")]
public DateTime Time { get; set; }
[Column("value")]
public decimal Price { get; set; }
[Column("figi")]
public required string Figi { get; set; }
[Column("ticker")]
public required string Ticker { get; set; }
[NotMapped]
public bool IsHistoricalData { get; set; }
[Column("count")]
public long Count { get; set; }
[Column("direction")]
public int Direction { get; set; }
[NotMapped]
public decimal Value { get; set; }
[NotMapped]
public decimal Value2 { get; set; }
[NotMapped]
public AttachedInfo? AttachedInfo
{
get
{
lock (_locker)
{
return _attachedInfo;
}
}
}
public void SetAttachedInfo(AttachedInfo? attachedInfo)
{
lock (_locker)
{
_attachedInfo = attachedInfo;
}
}
private AttachedInfo? _attachedInfo;
private readonly object _locker = new();
}
}

View File

@ -9,9 +9,12 @@ namespace KLHZ.Trader.Core.DataLayer
public class TraderDbContext : DbContext
{
public DbSet<Declision> Declisions { get; set; }
public DbSet<Trade> Trades { get; set; }
public DbSet<PriceChange> PriceChanges { get; set; }
public DbSet<ProcessedPrice> ProcessedPrices { get; set; }
public DbSet<ExperimentsResult> ExperimentsResults { get; set; }
public DbSet<OrderbookItem> OrderbookItems { get; set; }
public DbSet<OrderbookElement> OrderbookElements { get; set; }
public TraderDbContext(DbContextOptions<TraderDbContext> options)
: base(options)
{
@ -40,6 +43,26 @@ namespace KLHZ.Trader.Core.DataLayer
v => DateTime.SpecifyKind(v, DateTimeKind.Utc));
});
modelBuilder.Entity<Trade>(entity =>
{
entity.HasKey(e1 => new { e1.Time, e1.Id });
entity.Ignore(e1 => e1.IsHistoricalData);
entity.Property(e => e.Time)
.HasConversion(
v => v.ToUniversalTime(),
v => DateTime.SpecifyKind(v, DateTimeKind.Utc));
});
modelBuilder.Entity<ExperimentsResult>(entity =>
{
entity.HasKey(e1 => new { e1.Time, e1.Id });
entity.Ignore(e1 => e1.IsHistoricalData);
entity.Property(e => e.Time)
.HasConversion(
v => v.ToUniversalTime(),
v => DateTime.SpecifyKind(v, DateTimeKind.Utc));
});
modelBuilder.Entity<OrderbookItem>(entity =>
{
entity.HasKey(e1 => e1.Id);
@ -49,6 +72,15 @@ namespace KLHZ.Trader.Core.DataLayer
v => DateTime.SpecifyKind(v, DateTimeKind.Utc));
});
modelBuilder.Entity<OrderbookElement>(entity =>
{
entity.HasKey(e1 => new { e1.Time, e1.Id });
entity.Property(e => e.Time)
.HasConversion(
v => v.ToUniversalTime(),
v => DateTime.SpecifyKind(v, DateTimeKind.Utc));
});
modelBuilder.Entity<ProcessedPrice>(entity =>
{
entity.HasKey(e1 => e1.Id);

View File

@ -13,6 +13,7 @@ using Microsoft.Extensions.Options;
using System.Collections.Concurrent;
using Tinkoff.InvestApi;
using Tinkoff.InvestApi.V1;
using Trade = KLHZ.Trader.Core.DataLayer.Entities.Prices.Trade;
namespace KLHZ.Trader.Core.Exchange.Services
{
@ -137,14 +138,14 @@ namespace KLHZ.Trader.Core.Exchange.Services
});
var lastUpdateDict = new Dictionary<string, PriceChange>();
var pricesBuffer = new List<PriceChange>();
var pricesBuffer = new List<Trade>();
var orderbookItemsBuffer = new List<OrderbookItem>();
var lastWrite = DateTime.UtcNow;
await foreach (var response in stream.ResponseStream.ReadAllAsync())
{
if (response.Trade != null)
{
var message = new PriceChange()
var message = new Trade()
{
Figi = response.Trade.Figi,
Ticker = _tradeDataProvider.GetTickerByFigi(response.Trade.Figi),
@ -212,7 +213,7 @@ namespace KLHZ.Trader.Core.Exchange.Services
}
if (pricesBuffer.Count > 0)
{
await context.PriceChanges.AddRangeAsync(pricesBuffer);
await context.Trades.AddRangeAsync(pricesBuffer);
pricesBuffer.Clear();
}
await context.SaveChangesAsync();

View File

@ -351,5 +351,52 @@ namespace KLHZ.Trader.Service.Controllers
}
}
}
[HttpGet]
public async Task MigrateData()
{
try
{
using var context1 = await _dbContextFactory.CreateDbContextAsync();
context1.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking;
var figis = context1.PriceChanges.Select(p => p.Figi).Distinct().ToArray();
foreach (var f in figis)
{
try
{
var time1 = new DateTime(2025, 8, 25, 0, 0, 0, DateTimeKind.Utc);
while (time1 < DateTime.UtcNow)
{
var time2 = time1.AddDays(7);
var prices = await context1.PriceChanges
.Where(c => (c.Figi == f) && c.Time >= time1 && c.Time < time2)
.OrderBy(c => c.Time)
.ToArrayAsync();
await context1.Trades.AddRangeAsync(prices);
await context1.SaveChangesAsync();
time1 = time2;
}
}
catch (Exception ex)
{
}
}
}
catch (Exception ex)
{
}
}
}
}