using System; using System.Collections.Generic; namespace FinlyticEngine.Services.Ai; /// /// Outgoing request body for the n8n AI trade-validation webhook. Service-local (not FinlyticCore): this /// shape is an integration detail of only, not a cross-service MQTT /// contract (Rules.md §3 - core placement applies to data shared across services, not to a single service's /// own outbound HTTP integration). Serialized with JsonNamingPolicy.CamelCase, so every property here /// reaches n8n as camelCase without needing per-property [JsonPropertyName] attributes. /// public record N8nValidationRequestPayload( string Instructions, N8nAssetSection Asset, N8nTechnicalSetupSection TechnicalSetup, N8nWatchlistContextSection? WatchlistContext, N8nSentimentSection Sentiment, N8nFundamentalsSection Fundamentals, N8nReliabilitySection? Reliability, N8nScoreBreakdownSection ScoreBreakdown ); public record N8nAssetSection(string Isin, string Symbol, decimal CurrentPrice); public record N8nPatternSection(string Type, string Bias, decimal QualityScore, string Description); public record N8nTechnicalSetupSection( string Strategy, string StrategyName, string Direction, decimal Entry, decimal StopLoss, decimal TakeProfit1, decimal RiskRewardRatio, decimal QualityScore, string Rationale, string? MarketRegime, List TriggeringPatterns, Dictionary IndicatorSnapshot ); /// Why FinlyticTechnicals was even scanning this ISIN (see TechnicalUniverseManager). public record N8nWatchlistContextSection(string Source, DateTime EnteredAtUtc); public record N8nSentimentSection(string Label, double WeightedScore, string Trend, string LatestHighlight); /// /// Fundamental data + the two temporal suppression gates (/ /// ). Ratio fields (ReturnOnEquityRatio etc.) are /// forwarded as raw fractions (e.g. 0.15 = 15%) exactly as stored, rather than guessing a ×100 /// conversion that could silently misrepresent the source data (Rules.md §4). /// is the one exception: an honest, explicitly computed ratio (OperatingIncome / TotalRevenue × 100), only /// populated when both inputs are real numbers. /// public record N8nFundamentalsSection( decimal? ForwardPe, decimal? OperatingMarginPercent, decimal? RevenueGrowthYoYRatio, decimal? ReturnOnEquityRatio, decimal? DebtToEquity, decimal? FreeCashFlow, string? ConsensusRating, decimal? PriceTargetMean, decimal? ShortPercentOfFloatRatio, int? DaysToEarnings, bool PassedEarningsLockout, int? DaysToNextExDividend, bool PassedDividendGate ); /// FinlyticSimulation's backtest verdict for this exact (Isin, StrategyKey) - see . public record N8nReliabilitySection( decimal ReliabilityScore, decimal WinRatePercent, decimal ProfitFactor, int SampleTradeCount, bool IsStrategyApprovedForAsset, string RecommendedAction ); public record N8nScoreBreakdownSection( decimal CompositeScore, decimal TechnicalScore, decimal SentimentScore, decimal FundamentalScore, decimal ReliabilityBonus ); /// /// Expected shape of a successful n8n webhook response - deliberately identical field-for-field to /// (camelCase JSON) instead of the previous, /// undocumented ad hoc vocabulary (status/action_recommendation/raw_validation_result.*) /// that no prompt ever actually specified. is nullable because a validator that /// declines to give a numeric confidence must not have one fabricated for it (Rules.md §4). /// public record N8nValidationResponsePayload( bool? IsApproved, decimal? Confidence, string? ThesisSummary, string? InvalidationReason, List? KeyCatalysts, List? IdentifiedRisks );