feat(core): add shared DTOs, MqttTopics constants, DatabaseBootstrapper, and ManagedMqttClient extensions
This commit is contained in:
@@ -0,0 +1,110 @@
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace FinlyticCore.Dtos.Trading;
|
||||
|
||||
[JsonConverter(typeof(JsonStringEnumConverter<ExecutionMode>))]
|
||||
public enum ExecutionMode
|
||||
{
|
||||
SignalProposal, // Reines Signal zur manuellen Ansicht
|
||||
ManualTradeRepublic, // Händisch bei Trade Republic ausgeführt
|
||||
PaperTradingBot // Vollautomatisch im Paper-Trading-Modus
|
||||
}
|
||||
|
||||
[JsonConverter(typeof(JsonStringEnumConverter<TradeStatus>))]
|
||||
public enum TradeStatus
|
||||
{
|
||||
Proposed, // KI-geprüfter Vorschlag, wartet auf Ausführung
|
||||
Active, // Mindestens 1 Fill ausgeführt, Trade läuft
|
||||
BreakEvenTriggered, // Kurs hat TP1 erreicht, SL liegt auf Mischkurs
|
||||
Tp1Hit, // Teilverkauf 1 ausgeführt
|
||||
Tp2Hit, // Teilverkauf 2 ausgeführt
|
||||
Closed, // Vollständig mit Gewinn glattgestellt
|
||||
StoppedOut, // Durch Stop-Loss beendet
|
||||
Invalidated, // Kurs hat Invalidation erreicht, bevor Einstieg erfolgte
|
||||
Expired // Gültigkeitsfenster abgelaufen
|
||||
}
|
||||
|
||||
[JsonConverter(typeof(JsonStringEnumConverter<InstrumentCategoryType>))]
|
||||
public enum InstrumentCategoryType
|
||||
{
|
||||
Stock,
|
||||
Etf,
|
||||
TurboLong,
|
||||
TurboShort,
|
||||
FactorCertificate
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Identifies whether an <c>EngineEvaluationSnapshotEntity</c> row was produced by the autonomous
|
||||
/// <c>OpportunityPollerBackgroundService</c> scan loop or by an on-demand, human-initiated call (Web UI
|
||||
/// "Analyze now" / <c>EngineController.EvaluateAsset</c> / <c>AnalyzeController.TriggerManualAnalysis</c>).
|
||||
/// <see cref="Unknown"/> is deliberately value <c>0</c> (the default) so that snapshot rows written before
|
||||
/// this field existed - and any future row where the caller genuinely failed to specify a source - are never
|
||||
/// silently mis-reported as one of the two real sources (Rules.md §4: no fabricated data, an honest
|
||||
/// "we don't know" beats a fabricated default of <see cref="Automatic"/>).
|
||||
/// </summary>
|
||||
[JsonConverter(typeof(JsonStringEnumConverter<TriggerSource>))]
|
||||
public enum TriggerSource
|
||||
{
|
||||
Unknown = 0,
|
||||
Automatic = 1,
|
||||
Manual = 2
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Classifies why a single asset evaluation in <c>TradeLifecycleService.EvaluateAssetAsync</c> did or did not
|
||||
/// result in a trade proposal. <see cref="Unknown"/> is deliberately value <c>0</c> (the default) so snapshot
|
||||
/// rows persisted before this field existed read honestly as "reason unknown" rather than fabricating a
|
||||
/// specific-looking cause (Rules.md §4). See the "DetermineOutcomeReason" doc comment in
|
||||
/// <c>TradeLifecycleService</c> for the exact priority order applied when more than one gate failed at once.
|
||||
/// </summary>
|
||||
[JsonConverter(typeof(JsonStringEnumConverter<OutcomeReason>))]
|
||||
public enum OutcomeReason
|
||||
{
|
||||
Unknown = 0,
|
||||
|
||||
/// <summary>The AI reasoning gate approved the opportunity and a <c>EngineTradeProposalEntity</c> was created.</summary>
|
||||
Approved = 1,
|
||||
|
||||
/// <summary>
|
||||
/// <c>ScoringResult.CompositeScore</c> stayed below <c>Engine.MinCompositeScore</c> and the evaluation was
|
||||
/// not forced, so the AI reasoning gate was never even consulted (a synthetic rule-based rejection was
|
||||
/// recorded instead).
|
||||
/// </summary>
|
||||
BelowScoreThreshold = 2,
|
||||
|
||||
/// <summary>The asset is within the earnings blackout window (<c>Engine.EarningsLockoutDays</c>).</summary>
|
||||
EarningsLockout = 3,
|
||||
|
||||
/// <summary>FinlyticSimulation's backtest-reliability matrix vetoed this strategy/asset combination.</summary>
|
||||
SimulationVeto = 4,
|
||||
|
||||
/// <summary>
|
||||
/// The composite score cleared the minimum threshold (or the evaluation was forced) and neither the
|
||||
/// earnings-lockout nor the simulation-veto gate blocked it, but the AI reasoning gate itself - whether a
|
||||
/// real AI call or one of its own rule-based fallbacks (gate disabled, webhook unreachable) - still declined.
|
||||
/// </summary>
|
||||
AiRejected = 5,
|
||||
|
||||
/// <summary>
|
||||
/// No technical setup could be produced for the ISIN at all (FinlyticTechnicals returned nothing), or the
|
||||
/// ISIN itself was blank - in both cases the pipeline never reached scoring, so every score field on the
|
||||
/// snapshot is <c>0</c>/default rather than fabricated.
|
||||
/// </summary>
|
||||
NoTechnicalSetups = 6,
|
||||
|
||||
/// <summary>
|
||||
/// Not a real rejection: the evaluation genuinely cleared every gate and the AI reasoning gate approved the
|
||||
/// opportunity (<c>PassedAiValidation</c> on this same row is <see langword="true"/>), but an active,
|
||||
/// non-expired <c>EngineTradeProposalEntity</c> for the same <c>UnderlyingIsin</c> already exists, so no
|
||||
/// second, near-identical proposal row was created and no <c>finlytic/engine/proposals/created</c> MQTT
|
||||
/// event was re-broadcast. Exists specifically to stop the autonomous scanner from spamming a fresh
|
||||
/// proposal (and a fresh push event to every connected client) every single poll cycle for as long as one
|
||||
/// asset stays above the approval threshold - the underlying bug this value was introduced to fix.
|
||||
/// </summary>
|
||||
DuplicateActiveProposal = 7,
|
||||
|
||||
/// <summary>The asset is within the ex-dividend blackout window (<c>Engine.DividendGateDays</c>).</summary>
|
||||
DividendGate = 8
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user