Files
managing-apps/src/Managing.Domain/Strategies/Signals/StcIndicator.cs
Oda a547c4a040 Add synthApi (#27)
* Add synthApi

* Put confidence for Synth proba

* Update the code

* Update readme

* Fix bootstraping

* fix github build

* Update the endpoints for scenario

* Add scenario and update backtest modal

* Update bot modal

* Update interfaces for synth

* add synth to backtest

* Add Kelly criterion and better signal

* Update signal confidence

* update doc

* save leaderboard and prediction

* Update nswag to generate ApiClient in the correct path

* Unify the trading modal

* Save miner and prediction

* Update messaging and block new signal until position not close when flipping off

* Rename strategies to indicators

* Update doc

* Update chart + add signal name

* Fix signal direction

* Update docker webui

* remove crypto npm

* Clean
2025-07-03 00:13:42 +07:00

125 lines
3.7 KiB
C#

using Managing.Core;
using Managing.Domain.Candles;
using Managing.Domain.Shared.Rules;
using Managing.Domain.Strategies.Base;
using Skender.Stock.Indicators;
using static Managing.Common.Enums;
namespace Managing.Domain.Strategies.Signals;
public class StcIndicator : Indicator
{
public List<Signal> Signals { get; set; }
public StcIndicator(string name, int cyclePeriods, int fastPeriods, int slowPeriods) : base(name, IndicatorType.Stc)
{
Signals = new List<Signal>();
FastPeriods = fastPeriods;
SlowPeriods = slowPeriods;
CyclePeriods = cyclePeriods;
}
public override List<Signal> Run()
{
if (Candles.Count <= 2 * (SlowPeriods + CyclePeriods))
{
return null;
}
try
{
if (FastPeriods != null)
{
var stc = Candles.GetStc(FastPeriods.Value, FastPeriods.Value, SlowPeriods.Value).ToList();
if (CyclePeriods != null)
{
var stcCandles = MapStcToCandle(stc, Candles.TakeLast(CyclePeriods.Value));
if (stc.Count == 0)
return null;
var previousCandle = stcCandles[0];
foreach (var currentCandle in stcCandles.Skip(1))
{
if (previousCandle.Stc > 75 && currentCandle.Stc <= 75)
{
AddSignal(currentCandle, TradeDirection.Short, Confidence.Medium);
}
if (previousCandle.Stc < 25 && currentCandle.Stc >= 25)
{
AddSignal(currentCandle, TradeDirection.Long, Confidence.Medium);
}
previousCandle = currentCandle;
}
}
}
return Signals.Where(s => s.Confidence != Confidence.None).OrderBy(s => s.Date).ToList();
}
catch (RuleException)
{
return null;
}
}
public override IndicatorsResultBase GetIndicatorValues()
{
if (FastPeriods != null && SlowPeriods != null)
{
var stc = Candles.GetStc(FastPeriods.Value, FastPeriods.Value, SlowPeriods.Value).ToList();
return new IndicatorsResultBase
{
Stc = stc
};
}
return null;
}
private List<CandleSct> MapStcToCandle(List<StcResult> stc, IEnumerable<Candle> candles)
{
var sctList = new List<CandleSct>();
foreach (var candle in candles)
{
var currentSct = stc.Find(candle.Date);
if (currentSct != null)
{
sctList.Add(new CandleSct()
{
Close = candle.Close,
Open = candle.Open,
Date = candle.Date,
Ticker = candle.Ticker,
Exchange = candle.Exchange,
Stc = currentSct.Stc
});
}
}
return sctList;
}
private void AddSignal(CandleSct candleSignal, TradeDirection direction, Confidence confidence)
{
var signal = new Signal(
MiscExtensions.ParseEnum<Ticker>(candleSignal.Ticker),
direction,
confidence,
candleSignal,
candleSignal.Date,
candleSignal.Exchange,
Type, SignalType,
Name);
if (!Signals.Any(s => s.Identifier == signal.Identifier))
{
Signals.AddItem(signal);
}
}
private class CandleSct : Candle
{
public double? Stc { get; internal set; }
}
}