feat(engine): add FinlyticEngine microservice with trade lifecycle, AI reasoning gate, composite scoring, and unit tests
This commit is contained in:
@@ -0,0 +1,72 @@
|
||||
using FinlyticCore.Models.Settings;
|
||||
|
||||
namespace FinlyticEngine.Settings;
|
||||
|
||||
public static class EngineSettingKeys
|
||||
{
|
||||
// --- Logging Channels ---
|
||||
public static readonly SettingKey<bool> HealthPingChannel = new("Logging.Channel.Health", true);
|
||||
public static readonly SettingKey<bool> MqttChannel = new("Logging.Channel.MQTT", true);
|
||||
public static readonly SettingKey<bool> EngineChannel = new("Logging.Channel.Engine", true);
|
||||
public static readonly SettingKey<bool> ScoringChannel = new("Logging.Channel.Scoring", true);
|
||||
public static readonly SettingKey<bool> AiValidationChannel = new("Logging.Channel.AiValidation", true);
|
||||
public static readonly SettingKey<bool> DerivativesChannel = new("Logging.Channel.Derivatives", true);
|
||||
public static readonly SettingKey<bool> TradeLifecycleChannel = new("Logging.Channel.TradeLifecycle", true);
|
||||
|
||||
// --- Scoring & Multi-Factor Weights ---
|
||||
public static readonly SettingKey<decimal> MinCompositeScore = new("Engine.MinCompositeScore", 75.0m);
|
||||
public static readonly SettingKey<decimal> WeightTechnical = new("Engine.WeightTechnical", 0.45m);
|
||||
public static readonly SettingKey<decimal> WeightSentiment = new("Engine.WeightSentiment", 0.35m);
|
||||
public static readonly SettingKey<decimal> WeightFundamental = new("Engine.WeightFundamental", 0.20m);
|
||||
public static readonly SettingKey<int> EarningsLockoutDays = new("Engine.EarningsLockoutDays", 2);
|
||||
|
||||
/// <summary>
|
||||
/// Number of days before (and including) the ex-dividend date during which the composite score is
|
||||
/// moderately suppressed (see <c>CompositeOpportunityScorer</c>'s dividend gate). Smaller than
|
||||
/// <see cref="EarningsLockoutDays"/>'s default because an ex-dividend price adjustment is a predictable,
|
||||
/// mechanical gap-down (roughly the dividend amount), not a fundamental surprise like earnings.
|
||||
/// </summary>
|
||||
public static readonly SettingKey<int> DividendGateDays = new("Engine.DividendGateDays", 1);
|
||||
|
||||
// --- Knock-Out & Derivative Rules ---
|
||||
public static readonly SettingKey<decimal> MinDerivativeLeverage = new("Engine.MinDerivativeLeverage", 5.0m);
|
||||
public static readonly SettingKey<decimal> TargetDefaultLeverage = new("Engine.TargetDefaultLeverage", 7.0m);
|
||||
public static readonly SettingKey<decimal> KnockOutSafetyBufferPercent = new("Engine.KnockOutSafetyBufferPercent", 2.0m);
|
||||
|
||||
/// <summary>
|
||||
/// Seconds to wait for the n8n AI validation webhook before falling back to a rule-based decision. Was
|
||||
/// previously a hardcoded <c>TimeSpan.FromSeconds(15)</c> literal in <c>AiReasoningGateService</c>
|
||||
/// (Rules.md §12 forbids hardcoded values).
|
||||
/// </summary>
|
||||
public static readonly SettingKey<int> AiValidationTimeoutSeconds = new("Engine.AiValidationTimeoutSeconds", 15);
|
||||
|
||||
// --- Feature Toggles & Intervals ---
|
||||
public static readonly SettingKey<bool> EnableAiValidation = new("Engine.EnableAiValidation", true);
|
||||
public static readonly SettingKey<bool> EnablePaperTradingBot = new("Engine.EnablePaperTradingBot", false);
|
||||
public static readonly SettingKey<int> PollingIntervalSeconds = new("Engine.PollingIntervalSeconds", 120);
|
||||
public static readonly SettingKey<int> MonitoringIntervalSeconds = new("Engine.MonitoringIntervalSeconds", 60);
|
||||
|
||||
/// <summary>
|
||||
/// Minimum FinlyticTechnicals quality score a setup must clear before <c>OpportunityPollerBackgroundService</c>
|
||||
/// even asks the Engine to evaluate it. Was previously a hardcoded 70.0m literal on the <c>ta_GetSetups</c>
|
||||
/// request - not shown/tunable anywhere, and the reason "why don't I see any automatic evaluations" was
|
||||
/// impossible to answer from the admin UI.
|
||||
/// </summary>
|
||||
public static readonly SettingKey<decimal> PollerMinScore = new("Engine.PollerMinScore", 70.0m);
|
||||
|
||||
/// <summary>
|
||||
/// When true, the poller only requests FinlyticTechnicals' top-picks (quality score >= 75); when false it
|
||||
/// also considers any setup that cleared <see cref="PollerMinScore"/> without being a top pick.
|
||||
/// </summary>
|
||||
public static readonly SettingKey<bool> PollerTopPicksOnly = new("Engine.PollerTopPicksOnly", true);
|
||||
|
||||
/// <summary>Maximum number of setups FinlyticTechnicals returns per poll cycle.</summary>
|
||||
public static readonly SettingKey<int> PollerLimit = new("Engine.PollerLimit", 25);
|
||||
|
||||
/// <summary>
|
||||
/// Number of hours a freshly created trade proposal stays acceptable before it self-invalidates via
|
||||
/// <c>ExpiresAtUtc</c> (see <c>FinlyticEngine.Services.Trading.TradeLifecycleService.EvaluateAssetAsync</c>).
|
||||
/// Rules.md §12 forbids hardcoded values, so this was previously an inline <c>AddHours(24)</c> literal.
|
||||
/// </summary>
|
||||
public static readonly SettingKey<int> ProposalValidityHours = new("Engine.ProposalValidityHours", 24);
|
||||
}
|
||||
Reference in New Issue
Block a user