feat(technicals): add technical analysis microservice with indicator engines, pattern detectors, and strategies
This commit is contained in:
@@ -0,0 +1,47 @@
|
||||
using System;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
namespace FinlyticTechnicals.Entities;
|
||||
|
||||
[Table("fta_candles")]
|
||||
public class FtaCandleEntity
|
||||
{
|
||||
[Key]
|
||||
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
|
||||
public long Id { get; set; }
|
||||
|
||||
[Required]
|
||||
[MaxLength(20)]
|
||||
public string Isin { get; set; } = string.Empty;
|
||||
|
||||
[MaxLength(30)]
|
||||
public string Symbol { get; set; } = string.Empty;
|
||||
|
||||
[Required]
|
||||
[MaxLength(10)]
|
||||
public string Timeframe { get; set; } = "15m";
|
||||
|
||||
[Required]
|
||||
public DateTime TimestampUtc { get; set; }
|
||||
|
||||
[Column(TypeName = "decimal(18,4)")]
|
||||
public decimal Open { get; set; }
|
||||
|
||||
[Column(TypeName = "decimal(18,4)")]
|
||||
public decimal High { get; set; }
|
||||
|
||||
[Column(TypeName = "decimal(18,4)")]
|
||||
public decimal Low { get; set; }
|
||||
|
||||
[Column(TypeName = "decimal(18,4)")]
|
||||
public decimal Close { get; set; }
|
||||
|
||||
public long Volume { get; set; }
|
||||
|
||||
[Column(TypeName = "decimal(18,4)")]
|
||||
public decimal? Bid { get; set; }
|
||||
|
||||
[Column(TypeName = "decimal(18,4)")]
|
||||
public decimal? Ask { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
namespace FinlyticTechnicals.Entities;
|
||||
|
||||
[Table("fta_detected_patterns")]
|
||||
public class FtaDetectedPatternEntity
|
||||
{
|
||||
[Key]
|
||||
public Guid Id { get; set; } = Guid.NewGuid();
|
||||
|
||||
[Required]
|
||||
[MaxLength(20)]
|
||||
public string Isin { get; set; } = string.Empty;
|
||||
|
||||
[MaxLength(10)]
|
||||
public string Timeframe { get; set; } = "15m";
|
||||
|
||||
[Required]
|
||||
[MaxLength(50)]
|
||||
public string PatternType { get; set; } = string.Empty;
|
||||
|
||||
[MaxLength(30)]
|
||||
public string Category { get; set; } = string.Empty;
|
||||
|
||||
[MaxLength(20)]
|
||||
public string Bias { get; set; } = "Neutral";
|
||||
|
||||
[MaxLength(100)]
|
||||
public string Name { get; set; } = string.Empty;
|
||||
|
||||
[Column(TypeName = "decimal(18,4)")]
|
||||
public decimal KeyPriceLevel { get; set; }
|
||||
|
||||
[Column(TypeName = "decimal(18,4)")]
|
||||
public decimal UpperBoundary { get; set; }
|
||||
|
||||
[Column(TypeName = "decimal(18,4)")]
|
||||
public decimal LowerBoundary { get; set; }
|
||||
|
||||
[Column(TypeName = "decimal(18,4)")]
|
||||
public decimal InvalidationLevel { get; set; }
|
||||
|
||||
[Column(TypeName = "decimal(6,2)")]
|
||||
public decimal QualityScore { get; set; }
|
||||
|
||||
public string Description { get; set; } = string.Empty;
|
||||
|
||||
public Dictionary<string, object>? ExtraData { get; set; }
|
||||
|
||||
[Required]
|
||||
public DateTime DetectedAtUtc { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
using System;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
namespace FinlyticTechnicals.Entities;
|
||||
|
||||
/// <summary>
|
||||
/// Persisted backing store for <c>TechnicalUniverseManager</c>'s continuously-scanned asset universe (one row
|
||||
/// per monitored ISIN). Deliberately NOT meant to survive a service restart - <c>Program.cs</c> clears this
|
||||
/// table on every startup, since the universe is fully rebuilt within minutes from
|
||||
/// <c>RefreshFavoritesAsync</c>/<c>RefreshDiscoveryAsync</c> and fresh sentiment-spike events, and a stale row
|
||||
/// that never got TTL-swept because the process was down is worse than starting from an empty universe.
|
||||
/// </summary>
|
||||
[Table("fta_monitored_universe_assets")]
|
||||
public class FtaMonitoredUniverseAssetEntity
|
||||
{
|
||||
[Key]
|
||||
[MaxLength(20)]
|
||||
public string Isin { get; set; } = string.Empty;
|
||||
|
||||
[MaxLength(30)]
|
||||
public string? Symbol { get; set; }
|
||||
|
||||
/// <summary>String form of <c>FinlyticCore.Dtos.TechnicalAnalysis.UniverseSource</c>.</summary>
|
||||
[Required]
|
||||
[MaxLength(20)]
|
||||
public string Source { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>Lower value = higher scan priority (SentimentSpike=1, UserFavorite=2, Discovery=3).</summary>
|
||||
public int Priority { get; set; }
|
||||
|
||||
[Required]
|
||||
public DateTime AddedAtUtc { get; set; } = DateTime.UtcNow;
|
||||
|
||||
/// <summary><see langword="null"/> for favorites/discovery entries, which never expire by TTL.</summary>
|
||||
public DateTime? ExpiresAtUtc { get; set; }
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using FinlyticCore.Dtos.TechnicalAnalysis;
|
||||
|
||||
namespace FinlyticTechnicals.Entities;
|
||||
|
||||
[Table("fta_technical_setups")]
|
||||
public class FtaTechnicalSetupEntity
|
||||
{
|
||||
[Key]
|
||||
public Guid SetupId { get; set; } = Guid.NewGuid();
|
||||
|
||||
[Required]
|
||||
[MaxLength(20)]
|
||||
public string Isin { get; set; } = string.Empty;
|
||||
|
||||
[MaxLength(30)]
|
||||
public string Symbol { get; set; } = string.Empty;
|
||||
|
||||
[Required]
|
||||
[MaxLength(10)]
|
||||
public string Timeframe { get; set; } = "15m";
|
||||
|
||||
[Required]
|
||||
[MaxLength(50)]
|
||||
public string StrategyKey { get; set; } = string.Empty;
|
||||
|
||||
[MaxLength(100)]
|
||||
public string StrategyName { get; set; } = string.Empty;
|
||||
|
||||
[MaxLength(10)]
|
||||
public string Direction { get; set; } = "Buy";
|
||||
|
||||
[Column(TypeName = "decimal(6,2)")]
|
||||
public decimal QualityScore { get; set; }
|
||||
|
||||
[Column(TypeName = "decimal(18,4)")]
|
||||
public decimal CurrentPrice { get; set; }
|
||||
|
||||
[Column(TypeName = "decimal(18,4)")]
|
||||
public decimal EntryPrice { get; set; }
|
||||
|
||||
[Column(TypeName = "decimal(18,4)")]
|
||||
public decimal InvalidationPrice { get; set; }
|
||||
|
||||
[Column(TypeName = "decimal(18,4)")]
|
||||
public decimal CurrentAtr { get; set; }
|
||||
|
||||
[Column(TypeName = "decimal(8,2)")]
|
||||
public decimal EstimatedRiskRewardRatio { get; set; }
|
||||
|
||||
public ExitPlan ExitPlan { get; set; } = null!;
|
||||
|
||||
public string TechnicalRationale { get; set; } = string.Empty;
|
||||
|
||||
public List<PatternResultDto> TriggeringPatterns { get; set; } = [];
|
||||
|
||||
public Dictionary<string, decimal> IndicatorSnapshot { get; set; } = [];
|
||||
|
||||
public bool IsTopPick { get; set; }
|
||||
|
||||
[MaxLength(5)]
|
||||
public string Rating { get; set; } = "B";
|
||||
|
||||
public bool IsActive { get; set; } = true;
|
||||
|
||||
[Required]
|
||||
public DateTime CreatedAtUtc { get; set; } = DateTime.UtcNow;
|
||||
|
||||
[Required]
|
||||
public DateTime ExpiresAtUtc { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// String form of the <c>UniverseSource</c> this ISIN was being monitored under when this setup was
|
||||
/// computed (favorite/discovery/sentiment-spike), or <see langword="null"/> for an ad hoc analysis (e.g. a
|
||||
/// manual "Analyze now" call for an ISIN not currently in the scan universe). See
|
||||
/// <c>FinlyticCore.Dtos.TechnicalAnalysis.StrategyResultDto.UniverseSource</c>.
|
||||
/// </summary>
|
||||
[MaxLength(20)]
|
||||
public string? UniverseSource { get; set; }
|
||||
|
||||
/// <summary>When the ISIN above entered that scan universe, alongside <see cref="UniverseSource"/>.</summary>
|
||||
public DateTime? UniverseEnteredAtUtc { get; set; }
|
||||
|
||||
/// <summary>String form of the <c>MarketRegime</c> at analysis time. See <c>StrategyResultDto.Regime</c>.</summary>
|
||||
[MaxLength(30)]
|
||||
public string? Regime { get; set; }
|
||||
}
|
||||
Reference in New Issue
Block a user