using Bitget_Server.Application.State; using Bitget_Server.Domain; using Bitget_Server.Domain.Enums; using Bitget_Server.Domain.Models; using Bitget_Server.Infrastructure.Bitget; using Bitget_Server.Infrastructure.Utils; namespace Bitget_Server.Application.Services; /// /// 기존 MainForm.getMarketCandleData_WebService 이식. /// 신호 검색 대상 마켓/인터벌 조합의 초기 캔들 데이터를 일괄 로드한다. /// BitgetRateLimiter 를 자연스럽게 경유하므로 별도 Thread.Sleep(50) 이 불필요. /// public class InitialCandleLoader { private const int CandleCount = 200; private readonly BitgetClient _client; private readonly MarketState _state; private readonly ILogger _logger; public InitialCandleLoader(BitgetClient client, MarketState state, ILogger logger) { _client = client; _state = state; _logger = logger; } /// /// 체크된 마켓 목록에 대해 캔들 데이터를 채운다. /// public async Task LoadAsync(IEnumerable marketNames, IEnumerable intervalDescriptions, CancellationToken ct) { var intervalSet = new HashSet(intervalDescriptions ?? Array.Empty()); foreach (var marketName in marketNames ?? Array.Empty()) { if (ct.IsCancellationRequested) break; MarketCandleDataList marketCandleDataList; lock (_state.SyncRoot) { marketCandleDataList = _state.candleDataLists.Find(i => i.ConGoodsData?.MarketName == marketName); } if (marketCandleDataList == null) continue; foreach (MCandleTimeType interval in Enum.GetValues(typeof(MCandleTimeType))) { if (ct.IsCancellationRequested) break; var description = Convertor.GetEnumDescription(interval); if (!intervalSet.Contains(description)) continue; var url = string.Format( BitgetEndpoints.MarketCandle_Future, marketName, description, CandleCount.ToString(), "USDT-FUTURES"); try { await _client.SendWebServerAsync( ExchangeWebReqType.BitgetCandleStick_Future, url, marketCandleDataList, interval, ct: ct).ConfigureAwait(false); } catch (Exception ex) { _logger.LogWarning(ex, "초기 캔들 로드 실패 ({Market} / {Interval})", marketName, description); } } } } }