plug candle store and bot

This commit is contained in:
2025-09-14 16:21:48 +07:00
parent bac93199c0
commit caa0d9e1a6
5 changed files with 232 additions and 45 deletions

View File

@@ -16,7 +16,7 @@ public class CandleStoreGrain : Grain, ICandleStoreGrain, IAsyncObserver<Candle>
private readonly IPersistentState<CandleStoreGrainState> _state;
private readonly ILogger<CandleStoreGrain> _logger;
private readonly ICandleRepository _candleRepository;
private const int MaxCandleCount = 500;
private IAsyncStream<Candle> _priceStream;
private StreamSubscriptionHandle<Candle> _streamSubscription;
@@ -38,20 +38,7 @@ public class CandleStoreGrain : Grain, ICandleStoreGrain, IAsyncObserver<Candle>
_logger.LogInformation("CandleStoreGrain activated for key: {GrainKey}", grainKey);
// Parse the grain key to extract exchange, ticker, and timeframe
var parts = grainKey.Split('-');
if (parts.Length != 3)
{
_logger.LogError("Invalid grain key format: {GrainKey}. Expected format: Exchange-Ticker-Timeframe", grainKey);
return;
}
if (!Enum.TryParse<TradingExchanges>(parts[0], out var exchange) ||
!Enum.TryParse<Ticker>(parts[1], out var ticker) ||
!Enum.TryParse<Timeframe>(parts[2], out var timeframe))
{
_logger.LogError("Failed to parse grain key components: {GrainKey}", grainKey);
return;
}
var (exchange, ticker, timeframe) = CandleHelpers.ParseCandleStoreGrainKey(grainKey);
// Initialize state if empty
if (_state.State.Candles == null || _state.State.Candles.Count == 0)
@@ -95,7 +82,7 @@ public class CandleStoreGrain : Grain, ICandleStoreGrain, IAsyncObserver<Candle>
{
try
{
_logger.LogDebug("Received new candle for {GrainKey} at {Date}",
_logger.LogDebug("Received new candle for {GrainKey} at {Date}",
this.GetPrimaryKeyString(), candle.Date);
// Initialize state if needed
@@ -120,7 +107,7 @@ public class CandleStoreGrain : Grain, ICandleStoreGrain, IAsyncObserver<Candle>
// Persist the updated state
await _state.WriteStateAsync();
_logger.LogTrace("Updated candle store for {GrainKey}, total candles: {Count}",
_logger.LogTrace("Updated candle store for {GrainKey}, total candles: {Count}",
this.GetPrimaryKeyString(), _state.State.Candles.Count);
}
catch (Exception ex)
@@ -145,14 +132,17 @@ public class CandleStoreGrain : Grain, ICandleStoreGrain, IAsyncObserver<Candle>
{
try
{
_logger.LogInformation("Loading initial candles for {Exchange}-{Ticker}-{Timeframe}",
_logger.LogInformation("Loading initial candles for {Exchange}-{Ticker}-{Timeframe}",
exchange, ticker, timeframe);
// Load the last 500 candles from the database
var endDate = DateTime.UtcNow;
var startDate = endDate.AddDays(-30); // Look back 30 days to ensure we get enough data
var startDate =
CandleHelpers
.GetBotPreloadSinceFromTimeframe(timeframe); // Look back 30 days to ensure we get enough data
var candles = await _candleRepository.GetCandles(exchange, ticker, timeframe, startDate, endDate, MaxCandleCount);
var candles =
await _candleRepository.GetCandles(exchange, ticker, timeframe, startDate, endDate, MaxCandleCount);
if (candles?.Any() == true)
{
@@ -163,23 +153,23 @@ public class CandleStoreGrain : Grain, ICandleStoreGrain, IAsyncObserver<Candle>
await _state.WriteStateAsync();
_logger.LogInformation("Loaded {Count} initial candles for {Exchange}-{Ticker}-{Timeframe}",
_logger.LogInformation("Loaded {Count} initial candles for {Exchange}-{Ticker}-{Timeframe}",
_state.State.Candles.Count, exchange, ticker, timeframe);
}
else
{
_state.State.Candles = new List<Candle>();
await _state.WriteStateAsync();
_logger.LogWarning("No initial candles found for {Exchange}-{Ticker}-{Timeframe}",
_logger.LogWarning("No initial candles found for {Exchange}-{Ticker}-{Timeframe}",
exchange, ticker, timeframe);
}
}
catch (Exception ex)
{
_logger.LogError(ex, "Error loading initial candles for {Exchange}-{Ticker}-{Timeframe}",
_logger.LogError(ex, "Error loading initial candles for {Exchange}-{Ticker}-{Timeframe}",
exchange, ticker, timeframe);
// Initialize empty state on error
_state.State.Candles = new List<Candle>();
await _state.WriteStateAsync();
@@ -192,9 +182,9 @@ public class CandleStoreGrain : Grain, ICandleStoreGrain, IAsyncObserver<Candle>
{
var streamProvider = this.GetStreamProvider("DefaultStreamProvider");
_priceStream = streamProvider.GetStream<Candle>(streamKey);
_streamSubscription = await _priceStream.SubscribeAsync(this);
_logger.LogInformation("Subscribed to price stream for {StreamKey}", streamKey);
}
catch (Exception ex)
@@ -202,6 +192,11 @@ public class CandleStoreGrain : Grain, ICandleStoreGrain, IAsyncObserver<Candle>
_logger.LogError(ex, "Error subscribing to price stream for {StreamKey}", streamKey);
}
}
public Task<Candle> GetLastCandle()
{
return Task.FromResult(_state.State.Candles?.LastOrDefault());
}
}
/// <summary>
@@ -210,6 +205,5 @@ public class CandleStoreGrain : Grain, ICandleStoreGrain, IAsyncObserver<Candle>
[GenerateSerializer]
public class CandleStoreGrainState
{
[Id(0)]
public List<Candle> Candles { get; set; } = new();
[Id(0)] public List<Candle> Candles { get; set; } = new();
}