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; } }