using System;
using System.Collections.Generic;
namespace FinlyticCore.Dtos.TechnicalAnalysis;
///
/// Execution context supplied to pattern detectors and strategy evaluators containing multi-timeframe candles and indicators.
///
public class TechnicalContext
{
public string Isin { get; init; } = string.Empty;
public string Symbol { get; init; } = string.Empty;
public string Timeframe { get; init; } = "15m";
public DateTime TimestampUtc { get; init; } = DateTime.UtcNow;
public decimal CurrentPrice { get; init; }
public decimal CurrentSpread { get; init; }
public bool IsSpreadVolatile { get; init; }
public decimal CurrentAtr { get; init; }
public MarketRegime Regime { get; init; } = MarketRegime.LowVolatilityRangebound;
///
/// Multi-timeframe historical candles (e.g. "1m", "5m", "15m", "1h", "1d").
///
public Dictionary> MultiTimeframeCandles { get; init; } = new(StringComparer.OrdinalIgnoreCase);
///
/// Pre-calculated mathematical indicator values for the primary timeframe.
///
public Dictionary Indicators { get; init; } = new(StringComparer.OrdinalIgnoreCase);
///
/// Per-run overrides for a strategy's tunable indicator parameters (e.g. "MeanReversion.RsiOversold"),
/// keyed by "{StrategyKey}.{ParameterName}" so a single context could in principle carry overrides
/// for more than one strategy without name collisions. Always empty for live scanning
/// (TechnicalScoringEngine never populates this - Rules.md ยง4: no silent behavior change to live
/// trade generation as a side effect of a backtesting feature); populated only by
/// FinlyticSimulation.Engine.HistoricalReplayRunner from BacktestRequestDto.StrategyParameters,
/// so per-asset/per-strategy tuning is opt-in and scoped to backtesting. See .
///
public Dictionary ParameterOverrides { get; init; } = new(StringComparer.OrdinalIgnoreCase);
///
/// Resolves a tunable strategy parameter: the override in under
/// "{strategyKey}.{parameterName}" if present, otherwise (the
/// strategy's own hardcoded default, unchanged from before parametrization existed).
///
public decimal GetParameter(string strategyKey, string parameterName, decimal defaultValue)
{
return ParameterOverrides.TryGetValue($"{strategyKey}.{parameterName}", out var v) ? v : defaultValue;
}
///
/// Gets the candles for a specific timeframe (defaults to empty list if not found).
///
public IReadOnlyList GetCandles(string timeframe)
{
if (MultiTimeframeCandles.TryGetValue(timeframe, out var list))
{
return list;
}
return [];
}
///
/// Gets the primary timeframe candle sequence.
///
public IReadOnlyList PrimaryCandles => GetCandles(Timeframe);
///
/// Gets a specific indicator value or null if not computed.
///
public decimal? GetIndicator(string key)
{
if (Indicators.TryGetValue(key, out var val))
{
return val;
}
return null;
}
}