FrakTrak XonaX 策略
FrakTrak XonaX 是一种基于较大时间框架分形水平的突破策略。当价格突破最近的分形并额外移动 15 点时,策略沿突破方向入场。仓位通过固定止盈和跟踪止损进行管理。
参数
- Volume – 下单数量。
- Take Profit – 止盈距离(点)。
- Trailing Stop – 跟踪止损距离(点)。
- Trailing Correction – 跟踪止损的额外修正(点)。
- Candle Type – 构建蜡烛与分形所用的时间框架。
交易规则
- 使用最新完成的蜡烛计算上下分形。
- 当收盘价突破上分形并额外超过 15 点且当前没有多头头寸时买入。止损设在最近下分形,止盈按照 Take Profit 设置。
- 当收盘价跌破下分形并额外低于 15 点且当前没有空头头寸时卖出。止损设在最近上分形,止盈按照 Take Profit 设置。
- 当仓位盈利超过 Trailing Stop 点后,止损按照价格移动并加上 Trailing Correction 进行跟踪。
using System;
using System.Linq;
using System.Collections.Generic;
using Ecng.Common;
using Ecng.Collections;
using Ecng.Serialization;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// FrakTrak XonaX strategy.
/// Uses fractal breakouts to generate entry signals.
/// </summary>
public class FraktrakXonaxStrategy : Strategy
{
private readonly StrategyParam<decimal> _fractalOffset;
private readonly StrategyParam<DataType> _candleType;
private decimal _h1, _h2, _h3, _h4, _h5;
private decimal _l1, _l2, _l3, _l4, _l5;
private decimal? _upFractal;
private decimal? _downFractal;
private decimal? _lastUpFractal;
private decimal? _lastDownFractal;
/// <summary>
/// Price offset added beyond fractal for entry trigger.
/// </summary>
public decimal FractalOffset
{
get => _fractalOffset.Value;
set => _fractalOffset.Value = value;
}
/// <summary>
/// Candle type used by the strategy.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public FraktrakXonaxStrategy()
{
_fractalOffset = Param(nameof(FractalOffset), 50m)
.SetDisplay("Fractal Offset", "Price offset beyond fractal for entry", "Signals");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Source candles", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
=> [(Security, CandleType)];
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_h1 = _h2 = _h3 = _h4 = _h5 = 0m;
_l1 = _l2 = _l3 = _l4 = _l5 = 0m;
_upFractal = _downFractal = _lastUpFractal = _lastDownFractal = null;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var subscription = SubscribeCandles(CandleType);
subscription.Bind(ProcessCandle).Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle)
{
if (candle.State != CandleStates.Finished)
return;
// Shift high and low buffers
_h1 = _h2; _h2 = _h3; _h3 = _h4; _h4 = _h5; _h5 = candle.HighPrice;
_l1 = _l2; _l2 = _l3; _l3 = _l4; _l4 = _l5; _l5 = candle.LowPrice;
// Need at least 5 bars for fractal detection
if (_h1 == 0 || _l1 == 0)
return;
// Detect new fractals (bar 3 is the middle of 5 bars)
if (_h3 > _h1 && _h3 > _h2 && _h3 > _h4 && _h3 > _h5)
_upFractal = _h3;
if (_l3 < _l1 && _l3 < _l2 && _l3 < _l4 && _l3 < _l5)
_downFractal = _l3;
// Buy signal: close above up fractal + offset
if (_upFractal is decimal up && _lastUpFractal != up)
{
var trigger = up + FractalOffset;
if (candle.ClosePrice > trigger && Position <= 0)
{
BuyMarket();
_lastUpFractal = up;
}
}
// Sell signal: close below down fractal - offset
if (_downFractal is decimal low && _lastDownFractal != low)
{
var trigger = low - FractalOffset;
if (candle.ClosePrice < trigger && Position >= 0)
{
SellMarket();
_lastDownFractal = low;
}
}
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Strategies import Strategy
class fraktrak_xonax_strategy(Strategy):
def __init__(self):
super(fraktrak_xonax_strategy, self).__init__()
self._fractal_offset = self.Param("FractalOffset", 50.0) \
.SetDisplay("Fractal Offset", "Price offset beyond fractal for entry", "Signals")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Source candles", "General")
self._h1 = 0.0
self._h2 = 0.0
self._h3 = 0.0
self._h4 = 0.0
self._h5 = 0.0
self._l1 = 0.0
self._l2 = 0.0
self._l3 = 0.0
self._l4 = 0.0
self._l5 = 0.0
self._up_fractal = None
self._down_fractal = None
self._last_up_fractal = None
self._last_down_fractal = None
@property
def fractal_offset(self):
return self._fractal_offset.Value
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(fraktrak_xonax_strategy, self).OnReseted()
self._h1 = self._h2 = self._h3 = self._h4 = self._h5 = 0.0
self._l1 = self._l2 = self._l3 = self._l4 = self._l5 = 0.0
self._up_fractal = None
self._down_fractal = None
self._last_up_fractal = None
self._last_down_fractal = None
def OnStarted2(self, time):
super(fraktrak_xonax_strategy, self).OnStarted2(time)
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(self.process_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawOwnTrades(area)
def process_candle(self, candle):
if candle.State != CandleStates.Finished:
return
# Shift high and low buffers
self._h1 = self._h2
self._h2 = self._h3
self._h3 = self._h4
self._h4 = self._h5
self._h5 = float(candle.HighPrice)
self._l1 = self._l2
self._l2 = self._l3
self._l3 = self._l4
self._l4 = self._l5
self._l5 = float(candle.LowPrice)
# Need at least 5 bars for fractal detection
if self._h1 == 0 or self._l1 == 0:
return
# Detect new fractals (bar 3 is the middle of 5 bars)
if self._h3 > self._h1 and self._h3 > self._h2 and self._h3 > self._h4 and self._h3 > self._h5:
self._up_fractal = self._h3
if self._l3 < self._l1 and self._l3 < self._l2 and self._l3 < self._l4 and self._l3 < self._l5:
self._down_fractal = self._l3
close = float(candle.ClosePrice)
offset = float(self.fractal_offset)
# Buy signal: close above up fractal + offset
if self._up_fractal is not None and self._last_up_fractal != self._up_fractal:
trigger = self._up_fractal + offset
if close > trigger and self.Position <= 0:
self.BuyMarket()
self._last_up_fractal = self._up_fractal
# Sell signal: close below down fractal - offset
if self._down_fractal is not None and self._last_down_fractal != self._down_fractal:
trigger = self._down_fractal - offset
if close < trigger and self.Position >= 0:
self.SellMarket()
self._last_down_fractal = self._down_fractal
def CreateClone(self):
return fraktrak_xonax_strategy()