Stc opti (#15)

* Optimize STC

* Optimize STC

* Add SuperTrendCrossEma
This commit is contained in:
Oda
2025-03-01 02:59:19 +07:00
committed by GitHub
parent c715da8a17
commit e16f0a2e5d
13 changed files with 485 additions and 51 deletions

View File

@@ -153,7 +153,7 @@ namespace Managing.Application.Backtesting
} }
bot.Candles = new HashSet<Candle>(candles); bot.Candles = new HashSet<Candle>(candles);
// bot.UpdateStrategiesValues(); bot.UpdateStrategiesValues();
var strategies = _scenarioService.GetStrategies(); var strategies = _scenarioService.GetStrategies();
var strategiesValues = GetStrategiesValues(strategies, candles); var strategiesValues = GetStrategiesValues(strategies, candles);
@@ -176,12 +176,36 @@ namespace Managing.Application.Backtesting
Statistics = stats, Statistics = stats,
OptimizedMoneyManagement = optimizedMoneyManagement, OptimizedMoneyManagement = optimizedMoneyManagement,
MoneyManagement = moneyManagement, MoneyManagement = moneyManagement,
StrategiesValues = strategiesValues StrategiesValues = AggregateValues(strategiesValues, bot.StrategiesValues)
}; };
return result; return result;
} }
private Dictionary<StrategyType, StrategiesResultBase> AggregateValues(
Dictionary<StrategyType, StrategiesResultBase> strategiesValues,
Dictionary<StrategyType, StrategiesResultBase> botStrategiesValues)
{
// Foreach strategy type, only retrieve the values where the strategy is not present already in the bot
// Then, add the values to the bot values
var result = new Dictionary<StrategyType, StrategiesResultBase>();
foreach (var strategy in strategiesValues)
{
// if (!botStrategiesValues.ContainsKey(strategy.Key))
// {
// result[strategy.Key] = strategy.Value;
// }else
// {
// result[strategy.Key] = botStrategiesValues[strategy.Key];
// }
result[strategy.Key] = strategy.Value;
}
return result;
}
private Dictionary<StrategyType, StrategiesResultBase> GetStrategiesValues(IEnumerable<Strategy> strategies, private Dictionary<StrategyType, StrategiesResultBase> GetStrategiesValues(IEnumerable<Strategy> strategies,
List<Candle> candles) List<Candle> candles)
{ {

View File

@@ -60,7 +60,9 @@ public static class Enums
Composite, Composite,
StochRsiTrend, StochRsiTrend,
Stc, Stc,
StDev StDev,
LaggingStc,
SuperTrendCrossEma
} }
public enum SignalType public enum SignalType

View File

@@ -7,8 +7,6 @@ namespace Managing.Domain.Scenarios;
public static class ScenarioHelpers public static class ScenarioHelpers
{ {
public static IEnumerable<IStrategy> GetStrategiesFromScenario(Scenario scenario) public static IEnumerable<IStrategy> GetStrategiesFromScenario(Scenario scenario)
{ {
var strategies = new List<IStrategy>(); var strategies = new List<IStrategy>();
@@ -45,6 +43,10 @@ public static class ScenarioHelpers
strategy.SmoothPeriods.Value), strategy.SmoothPeriods.Value),
StrategyType.Stc => new STCStrategy(strategy.Name, strategy.CyclePeriods.Value, StrategyType.Stc => new STCStrategy(strategy.Name, strategy.CyclePeriods.Value,
strategy.FastPeriods.Value, strategy.SlowPeriods.Value), strategy.FastPeriods.Value, strategy.SlowPeriods.Value),
StrategyType.LaggingStc => new LaggingSTC(strategy.Name, strategy.CyclePeriods.Value,
strategy.FastPeriods.Value, strategy.SlowPeriods.Value),
StrategyType.SuperTrendCrossEma => new SuperTrendCrossEma(strategy.Name,
strategy.Period.Value, strategy.Multiplier.Value),
_ => throw new NotImplementedException(), _ => throw new NotImplementedException(),
}; };
@@ -101,6 +103,7 @@ public static class ScenarioHelpers
case StrategyType.ThreeWhiteSoldiers: case StrategyType.ThreeWhiteSoldiers:
break; break;
case StrategyType.SuperTrend: case StrategyType.SuperTrend:
case StrategyType.SuperTrendCrossEma:
case StrategyType.ChandelierExit: case StrategyType.ChandelierExit:
if (!period.HasValue || !multiplier.HasValue) if (!period.HasValue || !multiplier.HasValue)
{ {
@@ -132,6 +135,7 @@ public static class ScenarioHelpers
break; break;
case StrategyType.Stc: case StrategyType.Stc:
case StrategyType.LaggingStc:
if (!fastPeriods.HasValue || !slowPeriods.HasValue || !cyclePeriods.HasValue) if (!fastPeriods.HasValue || !slowPeriods.HasValue || !cyclePeriods.HasValue)
{ {
throw new Exception( throw new Exception(
@@ -168,6 +172,8 @@ public static class ScenarioHelpers
StrategyType.StochRsiTrend => SignalType.Trend, StrategyType.StochRsiTrend => SignalType.Trend,
StrategyType.Stc => SignalType.Signal, StrategyType.Stc => SignalType.Signal,
StrategyType.StDev => SignalType.Context, StrategyType.StDev => SignalType.Context,
StrategyType.LaggingStc => SignalType.Signal,
StrategyType.SuperTrendCrossEma => SignalType.Signal,
_ => throw new NotImplementedException(), _ => throw new NotImplementedException(),
}; };
} }

View File

@@ -21,13 +21,27 @@ public static class TradingBox
if (signals == null || signals.Count == 0) continue; if (signals == null || signals.Count == 0) continue;
var candleLoopback = limitedCandles.TakeLast(loopbackPeriod ?? 1).ToList(); // Ensure limitedCandles is ordered chronologically
var orderedCandles = limitedCandles.OrderBy(c => c.Date).ToList();
foreach (var signal in signals.Where(s => s.Date >= candleLoopback.FirstOrDefault()?.Date)) var loopback = loopbackPeriod ?? 1;
var candleLoopback = orderedCandles.TakeLast(loopback).ToList();
if (!candleLoopback.Any())
{ {
if (previousSignal.SingleOrDefault(s => s.Identifier == signal.Identifier) == null) // Handle empty case (e.g., log warning, skip processing)
continue;
}
var loopbackStartDate = candleLoopback.First().Date;
foreach (var signal in signals.Where(s => s.Date >= loopbackStartDate))
{
var hasExistingSignal = previousSignal.Any(s => s.Identifier == signal.Identifier);
if (!hasExistingSignal)
{ {
if (previousSignal.Count == 0 || previousSignal.Last().Date < signal.Date) bool shouldAdd = previousSignal.Count == 0 || previousSignal.Last().Date < signal.Date;
if (shouldAdd)
{ {
signalOnCandles.Add(signal); signalOnCandles.Add(signal);
} }

View File

@@ -0,0 +1,144 @@
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;
///<summary>
/// Lagging STC Strategy: Combines Schaff Trend Cycle with volatility-based confirmation.
/// Key Features:
/// 1. Short signals on STC breakdown from overbught (75+ → ≤75) with recent compressed volatility (min >78)
/// 2. Long signals on STC rebound from oversold (25- → ≥25) with recent compressed volatility (max <11)
/// 3. Avoids look-ahead bias through proper rolling window implementation
/// </summary>
public class LaggingSTC : Strategy
{
public List<Signal> Signals { get; set; }
public LaggingSTC(string name, int cyclePeriods, int fastPeriods, int slowPeriods) : base(name,
StrategyType.LaggingStc)
{
Signals = new List<Signal>();
FastPeriods = fastPeriods;
SlowPeriods = slowPeriods;
CyclePeriods = cyclePeriods;
}
public override List<Signal> Run()
{
if (Candles.Count <= 2 * (SlowPeriods + CyclePeriods))
{
return null;
}
try
{
var stc = Candles.GetStc(FastPeriods.Value, FastPeriods.Value, SlowPeriods.Value).ToList();
var stcCandles = MapStcToCandle(stc, Candles.TakeLast(CyclePeriods.Value * 3));
if (stcCandles.Count == 0)
return null;
for (int i = 1; i < stcCandles.Count; i++)
{
var currentCandle = stcCandles[i];
var previousCandle = stcCandles[i - 1];
/* VOLATILITY CONFIRMATION WINDOW
* - 22-period rolling window (≈1 trading month)
* - Ends at previous candle to avoid inclusion of current break
* - Dynamic sizing for early dataset cases */
// Calculate the lookback window ending at previousCandle (excludes currentCandle)
int windowSize = 32;
int windowStart = Math.Max(0, i - windowSize); // Ensure no negative indices
var lookbackWindow = stcCandles
.Skip(windowStart)
.Take(i - windowStart) // Take up to previousCandle (i-1)
.ToList();
double? minStc = lookbackWindow.Min(c => c.Stc);
double? maxStc = lookbackWindow.Max(c => c.Stc);
// Short Signal: Break below 75 with prior min >78
if (previousCandle.Stc > 75 && currentCandle.Stc <= 75)
{
if (minStc > 78)
{
AddSignal(currentCandle, TradeDirection.Short, Confidence.Medium);
}
}
// Long Signal: Break above 25 with prior max <11
if (previousCandle.Stc < 25 && currentCandle.Stc >= 25)
{
if (maxStc < 11)
{
AddSignal(currentCandle, TradeDirection.Long, Confidence.Medium);
}
}
}
return Signals.Where(s => s.Confidence != Confidence.None).OrderBy(s => s.Date).ToList();
}
catch (RuleException)
{
return null;
}
}
public override StrategiesResultBase GetStrategyValues()
{
var stc = Candles.GetStc(FastPeriods.Value, FastPeriods.Value, SlowPeriods.Value).ToList();
return new StrategiesResultBase
{
Stc = stc
};
}
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);
if (!Signals.Any(s => s.Identifier == signal.Identifier))
{
Signals.AddItem(signal);
}
}
private class CandleSct : Candle
{
public double? Stc { get; internal set; }
}
}

View File

@@ -0,0 +1,192 @@
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;
public class SuperTrendCrossEma : Strategy
{
public List<Signal> Signals { get; set; }
public SuperTrendCrossEma(string name, int period, double multiplier) : base(name, StrategyType.SuperTrendCrossEma)
{
Signals = new List<Signal>();
Period = period;
Multiplier = multiplier;
MinimumHistory = 100 + Period.Value;
}
public override List<Signal> Run()
{
// Validate sufficient historical data for all indicators
const int emaPeriod = 50;
const int adxPeriod = 14; // Standard ADX period
const int adxThreshold = 25; // Minimum ADX level to confirm a trend
int minimumRequiredHistory = Math.Max(Math.Max(emaPeriod, adxPeriod), Period.Value * 2); // Ensure enough data
if (Candles.Count < minimumRequiredHistory)
{
return null;
}
try
{
// 1. Calculate indicators
var superTrend = Candles.GetSuperTrend(Period.Value, Multiplier.Value)
.Where(s => s.SuperTrend.HasValue)
.ToList();
var ema50 = Candles.GetEma(emaPeriod)
.Where(e => e.Ema.HasValue)
.ToList();
var adxResults = Candles.GetAdx(adxPeriod)
.Where(a => a.Adx.HasValue && a.Pdi.HasValue && a.Mdi.HasValue) // Ensure all values exist
.ToList();
// 2. Create merged dataset with price + indicators
var superTrendCandles = MapSuperTrendToCandle(superTrend, Candles.TakeLast(minimumRequiredHistory));
if (superTrendCandles.Count == 0)
return null;
// 3. Add EMA50 and ADX values to the CandleSuperTrend objects
foreach (var candle in superTrendCandles)
{
var emaValue = ema50.Find(e => e.Date == candle.Date)?.Ema;
var adxValue = adxResults.Find(a => a.Date == candle.Date);
if (emaValue.HasValue)
candle.Ema50 = emaValue.Value;
if (adxValue != null)
{
candle.Adx = (decimal)adxValue.Adx.Value;
candle.Pdi = (decimal)adxValue.Pdi.Value;
candle.Mdi = (decimal)adxValue.Mdi.Value;
}
}
// 4. Signal detection logic with ADX filter
for (int i = 1; i < superTrendCandles.Count; i++)
{
var current = superTrendCandles[i];
var previous = superTrendCandles[i - 1];
// Convert SuperTrend to double for comparison
double currentSuperTrend = (double)current.SuperTrend;
double previousSuperTrend = (double)previous.SuperTrend;
// Ensure ADX data exists
if (current.Adx < adxThreshold) // Only trade when ADX confirms trend strength
continue;
/* LONG SIGNAL CONDITIONS:
* 1. SuperTrend crosses above EMA50
* 2. Price > SuperTrend and > EMA50
* 3. Previous state shows SuperTrend < EMA50
* 4. ADX > threshold and +DI > -DI (bullish momentum)
*/
bool longCross = currentSuperTrend > current.Ema50 &&
previousSuperTrend < previous.Ema50;
bool longPricePosition = current.Close > (decimal)currentSuperTrend &&
current.Close > (decimal)current.Ema50;
bool adxBullish = current.Pdi > current.Mdi; // Bullish momentum confirmation
if (longCross && longPricePosition && adxBullish)
{
AddSignal(current, TradeDirection.Long, Confidence.Medium);
}
/* SHORT SIGNAL CONDITIONS:
* 1. SuperTrend crosses below EMA50
* 2. Price < SuperTrend and < EMA50
* 3. Previous state shows SuperTrend > EMA50
* 4. ADX > threshold and -DI > +DI (bearish momentum)
*/
bool shortCross = currentSuperTrend < current.Ema50 &&
previousSuperTrend > previous.Ema50;
bool shortPricePosition = current.Close < (decimal)currentSuperTrend &&
current.Close < (decimal)current.Ema50;
bool adxBearish = current.Mdi > current.Pdi; // Bearish momentum confirmation
if (shortCross && shortPricePosition && adxBearish)
{
AddSignal(current, TradeDirection.Short, Confidence.Medium);
}
}
return Signals.Where(s => s.Confidence != Confidence.None)
.OrderBy(s => s.Date)
.ToList();
}
catch (RuleException)
{
return null;
}
}
private List<CandleSuperTrend> MapSuperTrendToCandle(List<SuperTrendResult> superTrend, IEnumerable<Candle> candles)
{
var superTrends = new List<CandleSuperTrend>();
foreach (var candle in candles)
{
var currentSuperTrend = superTrend.Find(candle.Date);
if (currentSuperTrend != null)
{
superTrends.Add(new CandleSuperTrend()
{
Close = candle.Close,
Open = candle.Open,
Date = candle.Date,
Ticker = candle.Ticker,
Exchange = candle.Exchange,
SuperTrend = currentSuperTrend.SuperTrend.Value,
LowerBand = currentSuperTrend.LowerBand,
UpperBand = currentSuperTrend.UpperBand,
});
}
}
return superTrends;
}
public override StrategiesResultBase GetStrategyValues()
{
return new StrategiesResultBase()
{
SuperTrend = Candles.GetSuperTrend(Period.Value, Multiplier.Value).Where(s => s.SuperTrend.HasValue)
.ToList()
};
}
private void AddSignal(CandleSuperTrend candleSignal, TradeDirection direction, Confidence confidence)
{
var signal = new Signal(MiscExtensions.ParseEnum<Ticker>(candleSignal.Ticker), direction, confidence,
candleSignal, candleSignal.Date,
candleSignal.Exchange, Type, SignalType);
if (!Signals.Any(s => s.Identifier == signal.Identifier))
{
Signals.AddItem(signal);
}
}
private class CandleSuperTrend : Candle
{
public decimal SuperTrend { get; internal set; }
public decimal? LowerBand { get; internal set; }
public decimal? UpperBand { get; internal set; }
public double Ema50 { get; set; }
public decimal Adx { get; set; } // ADX value
public decimal Pdi { get; set; } // Positive Directional Indicator (+DI)
public decimal Mdi { get; set; } // Negative Directional Indicator (-DI)
}
}

View File

@@ -394,7 +394,8 @@ public static class MongoMappers
Multiplier = strategyDto.Multiplier, Multiplier = strategyDto.Multiplier,
SmoothPeriods = strategyDto.SmoothPeriods, SmoothPeriods = strategyDto.SmoothPeriods,
StochPeriods = strategyDto.StochPeriods, StochPeriods = strategyDto.StochPeriods,
CyclePeriods = strategyDto.CyclePeriods CyclePeriods = strategyDto.CyclePeriods,
SignalType = strategyDto.SignalType
}; };
} }
@@ -404,44 +405,52 @@ public static class MongoMappers
{ {
Type = strategy.Type, Type = strategy.Type,
Name = strategy.Name, Name = strategy.Name,
SignalType = strategy.SignalType SignalType = strategy.SignalType,
CyclePeriods = strategy.CyclePeriods,
FastPeriods = strategy.FastPeriods,
Multiplier = strategy.Multiplier,
Period = strategy.Period,
SignalPeriods = strategy.SignalPeriods,
SlowPeriods = strategy.SlowPeriods,
SmoothPeriods = strategy.SmoothPeriods,
StochPeriods = strategy.StochPeriods
}; };
switch (strategy.Type) // switch (strategy.Type)
{ // {
case StrategyType.RsiDivergenceConfirm: // case StrategyType.RsiDivergenceConfirm:
case StrategyType.RsiDivergence: // case StrategyType.RsiDivergence:
case StrategyType.EmaCross: // case StrategyType.EmaCross:
case StrategyType.EmaTrend: // case StrategyType.EmaTrend:
case StrategyType.StDev: // case StrategyType.StDev:
dto.Period = strategy.Period; // dto.Period = strategy.Period;
break; // break;
case StrategyType.MacdCross: // case StrategyType.MacdCross:
dto.SlowPeriods = strategy.SlowPeriods; // dto.SlowPeriods = strategy.SlowPeriods;
dto.FastPeriods = strategy.FastPeriods; // dto.FastPeriods = strategy.FastPeriods;
dto.SignalPeriods = strategy.SignalPeriods; // dto.SignalPeriods = strategy.SignalPeriods;
break; // break;
case StrategyType.ThreeWhiteSoldiers: // case StrategyType.ThreeWhiteSoldiers:
break; // break;
case StrategyType.ChandelierExit: // case StrategyType.ChandelierExit:
case StrategyType.SuperTrend: // case StrategyType.SuperTrend:
dto.Period = strategy.Period; // dto.Period = strategy.Period;
dto.Multiplier = strategy.Multiplier; // dto.Multiplier = strategy.Multiplier;
break; // break;
case StrategyType.StochRsiTrend: // case StrategyType.StochRsiTrend:
dto.Period = strategy.Period; // dto.Period = strategy.Period;
dto.StochPeriods = strategy.StochPeriods; // dto.StochPeriods = strategy.StochPeriods;
dto.SignalPeriods = strategy.SignalPeriods; // dto.SignalPeriods = strategy.SignalPeriods;
dto.SmoothPeriods = strategy.SmoothPeriods; // dto.SmoothPeriods = strategy.SmoothPeriods;
break; // break;
case StrategyType.Stc: // case StrategyType.Stc:
dto.SlowPeriods = strategy.SlowPeriods; // dto.SlowPeriods = strategy.SlowPeriods;
dto.FastPeriods = strategy.FastPeriods; // dto.FastPeriods = strategy.FastPeriods;
dto.CyclePeriods = strategy.CyclePeriods; // dto.CyclePeriods = strategy.CyclePeriods;
break; // break;
default: // default:
break; // break;
} // }
return dto; return dto;
} }

View File

@@ -1,12 +1,15 @@
import { TradeChart, CardPositionItem } from '..' import { TradeChart, CardPositionItem } from '..'
import { IBotRowDetails } from '../../../global/type' import { IBotRowDetails } from '../../../global/type'
import { CardPosition } from '../../mollecules' import { CardPosition, CardText } from '../../mollecules'
const BacktestRowDetails: React.FC<IBotRowDetails> = ({ const BacktestRowDetails: React.FC<IBotRowDetails> = ({
candles, candles,
positions, positions,
walletBalances, walletBalances,
strategiesValues, strategiesValues,
signals,
optimizedMoneyManagement,
statistics
}) => { }) => {
return ( return (
<> <>
@@ -27,17 +30,42 @@ const BacktestRowDetails: React.FC<IBotRowDetails> = ({
})} })}
></CardPosition> ></CardPosition>
<CardPositionItem positions={positions}></CardPositionItem> <CardPositionItem positions={positions}></CardPositionItem>
<CardText
title="Optimized Money Management"
content={
"SL: " +optimizedMoneyManagement.stopLoss.toFixed(2) + "% TP: " + optimizedMoneyManagement.takeProfit.toFixed(2) + "%"
}
></CardText>
<CardText
title="Max Drowdown"
content={
statistics.maxDrawdown?.toFixed(4).toString() +
'$'
}
></CardText>
<CardText
title="Sharpe Ratio"
content={
(statistics.sharpeRatio
? statistics.sharpeRatio * 100
: 0
)
.toFixed(4)
.toString() + '%'
}
></CardText>
</div> </div>
<div> <div>
<figure> <figure>
<TradeChart <TradeChart
width={1400} width={1400}
height={1400} height={1100}
candles={candles} candles={candles}
positions={positions} positions={positions}
walletBalances={walletBalances} walletBalances={walletBalances}
strategiesValues={strategiesValues} strategiesValues={strategiesValues}
signals={[]} signals={signals}
></TradeChart> ></TradeChart>
</figure> </figure>
</div> </div>

View File

@@ -248,12 +248,16 @@ const BacktestTable: React.FC<IBacktestCards> = ({ list, isFetching }) => {
positions={row.original.positions} positions={row.original.positions}
walletBalances={row.original.walletBalances} walletBalances={row.original.walletBalances}
strategiesValues={row.original.strategiesValues} strategiesValues={row.original.strategiesValues}
signals={row.original.signals}
optimizedMoneyManagement={row.original.optimizedMoneyManagement}
statistics={row.original.statistics}
></BacktestRowDetails> ></BacktestRowDetails>
</> </>
), ),
[] []
) )
return ( return (
<div <div
className="flex flex-wrap" className="flex flex-wrap"
@@ -261,13 +265,14 @@ const BacktestTable: React.FC<IBacktestCards> = ({ list, isFetching }) => {
> >
{isFetching ? ( {isFetching ? (
<progress className="progress progress-primary w-56"></progress> <progress className="progress progress-primary w-56"></progress>
) : ( ) : (<>
<Table <Table
columns={columns} columns={columns}
data={rows} data={rows}
renderRowSubCompontent={renderRowSubComponent} renderRowSubCompontent={renderRowSubComponent}
showPagination={true} showPagination={true}
/> />
</>
)} )}
</div> </div>
) )

View File

@@ -92,6 +92,8 @@ const TradeChart = ({
bottomLineColor: theme.secondary, bottomLineColor: theme.secondary,
topLineColor: theme.primary, topLineColor: theme.primary,
lineWidth: 1, lineWidth: 1,
priceLineVisible: true,
crosshairMarkerVisible: true,
} as BaselineSeriesOptions } as BaselineSeriesOptions
function buildMarker( function buildMarker(
@@ -406,6 +408,7 @@ const TradeChart = ({
stcSeries.setData(stcData) stcSeries.setData(stcData)
stcSeries.applyOptions({ stcSeries.applyOptions({
...baselineOptions, ...baselineOptions,
priceLineVisible: true,
priceFormat: { priceFormat: {
minMove: 1, minMove: 1,
precision: 1, precision: 1,

View File

@@ -2233,6 +2233,8 @@ export enum StrategyType {
StochRsiTrend = "StochRsiTrend", StochRsiTrend = "StochRsiTrend",
Stc = "Stc", Stc = "Stc",
StDev = "StDev", StDev = "StDev",
LaggingStc = "LaggingStc",
SuperTrendCrossEma = "SuperTrendCrossEma",
} }
export enum SignalType { export enum SignalType {

View File

@@ -13,6 +13,7 @@ import type {
IFlow, IFlow,
KeyValuePairOfDateTimeAndDecimal, KeyValuePairOfDateTimeAndDecimal,
MoneyManagement, MoneyManagement,
PerformanceMetrics,
Position, Position,
RiskLevel, RiskLevel,
Scenario, Scenario,
@@ -147,6 +148,9 @@ export type IBotRowDetails = {
positions: Position[] positions: Position[]
walletBalances?: KeyValuePairOfDateTimeAndDecimal[] | null walletBalances?: KeyValuePairOfDateTimeAndDecimal[] | null
strategiesValues?: { [key in keyof typeof StrategyType]?: StrategiesResultBase; } | null; strategiesValues?: { [key in keyof typeof StrategyType]?: StrategiesResultBase; } | null;
signals: Signal[]
optimizedMoneyManagement: MoneyManagement
statistics: PerformanceMetrics
} }
export type IBacktestFormInput = { export type IBacktestFormInput = {

View File

@@ -227,7 +227,7 @@ const StrategyList: React.FC = () => {
</> </>
) : null} ) : null}
{strategyType == StrategyType.Stc ? ( {strategyType == StrategyType.Stc || strategyType == StrategyType.LaggingStc ? (
<> <>
<div className="form-control"> <div className="form-control">
<div className="input-group"> <div className="input-group">
@@ -278,6 +278,7 @@ const StrategyList: React.FC = () => {
) : null} ) : null}
{strategyType == StrategyType.SuperTrend || {strategyType == StrategyType.SuperTrend ||
strategyType == StrategyType.SuperTrendCrossEma ||
strategyType == StrategyType.ChandelierExit ? ( strategyType == StrategyType.ChandelierExit ? (
<> <>
<div className="form-control"> <div className="form-control">