Add endpoint for indicator refiner
This commit is contained in:
@@ -1,12 +1,15 @@
|
||||
using Managing.Application.Abstractions.Repositories;
|
||||
using Managing.Application.Abstractions.Services;
|
||||
using Managing.Domain.Accounts;
|
||||
using Managing.Domain.Backtests;
|
||||
using Managing.Domain.Bots;
|
||||
using Managing.Domain.Candles;
|
||||
using Managing.Domain.Indicators;
|
||||
using Managing.Domain.Scenarios;
|
||||
using Managing.Domain.Shared.Helpers;
|
||||
using Managing.Domain.Statistics;
|
||||
using Managing.Domain.Strategies;
|
||||
using Managing.Domain.Strategies.Base;
|
||||
using Managing.Domain.Synth.Models;
|
||||
using Managing.Domain.Trades;
|
||||
using Managing.Domain.Users;
|
||||
@@ -491,4 +494,141 @@ public class TradingService : ITradingService
|
||||
throw new InvalidOperationException($"Failed to swap GMX tokens: {ex.Message}", ex);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Calculates indicator values and generates signals for a given ticker, timeframe, and date range with selected indicators.
|
||||
/// </summary>
|
||||
public async Task<RefineIndicatorsResult> RefineIndicatorsAsync(
|
||||
Ticker ticker,
|
||||
Timeframe timeframe,
|
||||
DateTime startDate,
|
||||
DateTime endDate,
|
||||
List<IndicatorRequest> indicators)
|
||||
{
|
||||
// Get candles for the specified period
|
||||
var candles = await _exchangeService.GetCandlesInflux(
|
||||
TradingExchanges.Evm,
|
||||
ticker,
|
||||
startDate,
|
||||
timeframe,
|
||||
endDate);
|
||||
|
||||
if (candles == null || candles.Count == 0)
|
||||
{
|
||||
return new RefineIndicatorsResult
|
||||
{
|
||||
IndicatorsValues = new Dictionary<IndicatorType, IndicatorsResultBase>(),
|
||||
Signals = new List<LightSignal>()
|
||||
};
|
||||
}
|
||||
|
||||
// Convert to ordered List to preserve chronological order for indicators
|
||||
var candlesList = candles.OrderBy(c => c.Date).ToList();
|
||||
|
||||
// Map request indicators to domain Scenario
|
||||
var scenario = MapRefineIndicatorsToScenario(indicators);
|
||||
|
||||
// Calculate indicators values
|
||||
var indicatorsValues = TradingBox.CalculateIndicatorsValues(scenario, candlesList);
|
||||
|
||||
// Generate signals for the date range using rolling window approach
|
||||
var signals = GenerateSignalsForDateRange(candlesList, scenario, indicatorsValues);
|
||||
|
||||
return new RefineIndicatorsResult
|
||||
{
|
||||
IndicatorsValues = indicatorsValues,
|
||||
Signals = signals
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Maps IndicatorRequest list to a domain Scenario object.
|
||||
/// </summary>
|
||||
private Scenario MapRefineIndicatorsToScenario(List<IndicatorRequest> indicators)
|
||||
{
|
||||
var scenario = new Scenario("RefineIndicators", 1);
|
||||
|
||||
foreach (var indicatorRequest in indicators)
|
||||
{
|
||||
var indicator = new IndicatorBase(indicatorRequest.Name, indicatorRequest.Type)
|
||||
{
|
||||
SignalType = indicatorRequest.SignalType,
|
||||
MinimumHistory = indicatorRequest.MinimumHistory,
|
||||
Period = indicatorRequest.Period,
|
||||
FastPeriods = indicatorRequest.FastPeriods,
|
||||
SlowPeriods = indicatorRequest.SlowPeriods,
|
||||
SignalPeriods = indicatorRequest.SignalPeriods,
|
||||
Multiplier = indicatorRequest.Multiplier,
|
||||
StDev = indicatorRequest.StDev,
|
||||
SmoothPeriods = indicatorRequest.SmoothPeriods,
|
||||
StochPeriods = indicatorRequest.StochPeriods,
|
||||
CyclePeriods = indicatorRequest.CyclePeriods,
|
||||
KFactor = indicatorRequest.KFactor,
|
||||
DFactor = indicatorRequest.DFactor,
|
||||
TenkanPeriods = indicatorRequest.TenkanPeriods,
|
||||
KijunPeriods = indicatorRequest.KijunPeriods,
|
||||
SenkouBPeriods = indicatorRequest.SenkouBPeriods,
|
||||
OffsetPeriods = indicatorRequest.OffsetPeriods,
|
||||
SenkouOffset = indicatorRequest.SenkouOffset,
|
||||
ChikouOffset = indicatorRequest.ChikouOffset
|
||||
};
|
||||
|
||||
scenario.AddIndicator(indicator);
|
||||
}
|
||||
|
||||
return scenario;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generates signals for a date range using a rolling window approach.
|
||||
/// </summary>
|
||||
private List<LightSignal> GenerateSignalsForDateRange(
|
||||
List<Candle> candles,
|
||||
Scenario scenario,
|
||||
Dictionary<IndicatorType, IndicatorsResultBase> preCalculatedIndicatorValues)
|
||||
{
|
||||
var allSignals = new List<LightSignal>();
|
||||
var previousSignals = new Dictionary<string, LightSignal>();
|
||||
var lightScenario = LightScenario.FromScenario(scenario);
|
||||
|
||||
// Use rolling window approach similar to backtests
|
||||
const int RollingWindowSize = 600;
|
||||
var rollingWindowCandles = new List<Candle>(RollingWindowSize);
|
||||
|
||||
foreach (var candle in candles)
|
||||
{
|
||||
// Maintain rolling window
|
||||
if (rollingWindowCandles.Count >= RollingWindowSize)
|
||||
{
|
||||
rollingWindowCandles.RemoveAt(0);
|
||||
}
|
||||
rollingWindowCandles.Add(candle);
|
||||
|
||||
// Only process if we have enough candles for indicators
|
||||
if (rollingWindowCandles.Count < 2)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Generate signal for current position
|
||||
var signal = TradingBox.GetSignal(
|
||||
rollingWindowCandles,
|
||||
lightScenario,
|
||||
previousSignals,
|
||||
scenario.LookbackPeriod,
|
||||
preCalculatedIndicatorValues);
|
||||
|
||||
if (signal != null)
|
||||
{
|
||||
// Check if this is a new signal (not already in our collection)
|
||||
if (!previousSignals.ContainsKey(signal.Identifier))
|
||||
{
|
||||
allSignals.Add(signal);
|
||||
previousSignals[signal.Identifier] = signal;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return allSignals.OrderBy(s => s.Date).ToList();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user