klhztrader/KLHZ.Trader.Core/Exchange/Models/AssetsAccounting/ManagedAccount.cs

259 lines
11 KiB
C#

using System.Collections.Concurrent;
namespace KLHZ.Trader.Core.Exchange.Models.AssetsAccounting
{
public class ManagedAccount
{
public readonly string AccountId;
private readonly object _locker = new();
private decimal _balance = 0;
private decimal _total = 0;
internal decimal Balance
{
get
{
lock (_locker)
return _balance;
}
set
{
lock (_locker)
_balance = value;
}
}
internal decimal Total
{
get
{
lock (_locker)
return _total;
}
set
{
lock (_locker)
_total = value;
}
}
internal readonly ConcurrentDictionary<string, Asset> Assets = new();
public ManagedAccount(string accountId)
{
AccountId = accountId;
}
// private async Task ProcessCommands()
// {
// while (await _channel.Reader.WaitToReadAsync())
// {
// var command = await _channel.Reader.ReadAsync();
// try
// {
// await ProcessMarketCommand(command);
// }
// catch (Exception ex)
// {
// _logger.LogError(ex, "Ошибка при обработке команды.");
// }
// }
// }
// internal async Task SyncPortfolio()
// {
// try
// {
// //await _semaphoreSlim.WaitAsync();
// var portfolio = await _investApiClient.Operations.GetPortfolioAsync(new PortfolioRequest()
// {
// AccountId = AccountId,
// });
// var oldAssets = Assets.Keys.ToHashSet();
// using var context = await _dbContextFactory.CreateDbContextAsync();
// context.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking;
// var trades = await context.Trades
// .Where(t => t.AccountId == AccountId && t.ArchiveStatus == 0)
// .ToListAsync();
// foreach (var position in portfolio.Positions)
// {
// decimal price = 0;
// var trade = trades.FirstOrDefault(t => t.Figi == position.Figi);
// if (trade != null)
// {
// trades.Remove(trade);
// price = trade.Price;
// }
// else
// {
// price = position.AveragePositionPrice;
// }
//#pragma warning disable CS0612 // Тип или член устарел
// var asset = new Models.Assets.Asset()
// {
// TradeId = trade?.Id,
// AccountId = AccountId,
// Figi = position.Figi,
// Ticker = position.Ticker,
// BoughtAt = trade?.BoughtAt ?? DateTime.UtcNow,
// BoughtPrice = price,
// Type = position.InstrumentType.ParseInstrumentType(),
// Position = position.Quantity > 0 ? PositionType.Long : PositionType.Short,
// BlockedItems = position.BlockedLots,
// Count = position.Quantity,
// CountLots = position.QuantityLots,
// };
//#pragma warning restore CS0612 // Тип или член устарел
// Assets.AddOrUpdate(asset.Figi, asset, (k, v) => asset);
// oldAssets.Remove(asset.Figi);
// }
// Total = portfolio.TotalAmountPortfolio;
// Balance = portfolio.TotalAmountCurrencies;
// foreach (var asset in oldAssets)
// {
// Assets.TryRemove(asset, out _);
// }
// var ids = trades.Select(t => t.Id).ToArray();
// await context.Trades
// .Where(t => ids.Contains(t.Id))
// .ExecuteUpdateAsync(t => t.SetProperty(tr => tr.ArchiveStatus, 1));
// }
// catch (Exception ex)
// {
// _logger.LogError(ex, "Ошибка при синхранизации портфеля счёта {accountId}", AccountId);
// }
// finally
// {
// //_semaphoreSlim.Release();
// }
// }
// internal async Task<DealResult> ClosePosition(string figi)
// {
// if (!string.IsNullOrEmpty(figi) && Assets.TryGetValue(figi, out var asset))
// {
// try
// {
// var req = new PostOrderRequest()
// {
// AccountId = AccountId,
// InstrumentId = figi,
// };
// if (asset != null)
// {
// req.Direction = OrderDirection.Sell;
// req.OrderType = OrderType.Market;
// req.Quantity = (long)asset.Count;
// req.ConfirmMarginTrade = true;
// var res = await _investApiClient.Orders.PostOrderAsync(req);
// return new DealResult
// {
// Count = res.LotsExecuted,
// Price = res.ExecutedOrderPrice,
// Success = true,
// };
// }
// }
// catch (Exception ex)
// {
// _logger.LogError(ex, "Ошибка при закрытии позиции по счёту {acc}. figi: {figi}", AccountId, figi);
// }
// }
// return new DealResult
// {
// Count = 0,
// Price = 0,
// Success = false,
// };
// }
// internal async Task<DealResult> BuyAsset(string figi, decimal count, string? ticker = null, decimal? recommendedPrice = null)
// {
// try
// {
// var req = new PostOrderRequest()
// {
// AccountId = AccountId,
// InstrumentId = figi,
// Direction = OrderDirection.Buy,
// OrderType = OrderType.Market,
// Quantity = (long)count,
// };
// var res = await _investApiClient.Orders.PostOrderAsync(req);
// using var context = await _dbContextFactory.CreateDbContextAsync();
// context.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking;
// var trade = await context.Trades.FirstOrDefaultAsync(t => t.ArchiveStatus == 0 && t.Figi == figi);
// if (trade == null)
// {
// var newTrade = new DataLayer.Entities.Trades.Trade()
// {
// AccountId = AccountId,
// Figi = figi,
// Ticker = ticker ?? string.Empty,
// BoughtAt = DateTime.UtcNow,
// Count = res.LotsExecuted,
// Price = res.ExecutedOrderPrice,
// Position = DataLayer.Entities.Trades.Enums.PositionType.Long,
// Direction = DataLayer.Entities.Trades.Enums.TradeDirection.Buy,
// Asset = DataLayer.Entities.Trades.Enums.AssetType.Common,
// };
// await context.Trades.AddAsync(newTrade);
// }
// else
// {
// var oldAmount = trade.Price * trade.Count;
// var newAmount = res.ExecutedOrderPrice * res.LotsExecuted;
// trade.Count = res.LotsExecuted + trade.Count;
// trade.Price = (oldAmount + newAmount) / trade.Count;
// context.Trades.Update(trade);
// }
// await context.SaveChangesAsync();
// return new DealResult
// {
// Count = res.LotsExecuted,
// Price = res.ExecutedOrderPrice,
// Success = true,
// };
// }
// catch (Exception ex)
// {
// _logger.LogError(ex, "Ошибка при покупке актива на счёт {acc}. figi: {figi}", AccountId, figi);
// }
// return new DealResult
// {
// Count = 0,
// Price = 0,
// Success = false,
// };
// }
// private async Task ProcessMarketCommand(TradeCommand command)
// {
// if (string.IsNullOrWhiteSpace(command.Figi)) return;
// if (command.CommandType == TradeCommandType.MarketBuy)
// {
// await BuyAsset(command.Figi, command.Count ?? 1, command.Ticker, command.RecomendPrice);
// }
// else if (command.CommandType == TradeCommandType.ForceClosePosition)
// {
// await ClosePosition(command.Figi);
// }
// else return;
// await SyncPortfolio();
// }
}
}