TMA 突破策略
该策略利用三角移动平均线(TMA)突破信号进行交易。它监控指定周期的K线,将上一根K线的收盘价与TMA值加/减用户设置的偏移量进行比较。当上一根K线收盘价高于 TMA + UpLevel 时开多单;当收盘价低于 TMA - DownLevel 时开空单。相反信号会反向持仓。
参数
- TMA Length – 三角移动平均线的周期。
- Upper Level – 用于判断多头信号的价格偏移量。
- Lower Level – 用于判断空头信号的价格偏移量。
- Candle Type – 策略使用的K线周期。
工作原理
- 订阅所选证券的K线数据。
- 将三角移动平均线指标绑定到K线。
- 每当一根K线完成时:
- 保存前一根K线的TMA值和收盘价。
- 检查前一根收盘价是否突破上下偏移。
- 根据结果发送市价单并反转仓位。
- 在图表上绘制K线、指标和自身交易。
注意
该策略仅用于演示,不包含止损或止盈机制。真实交易前需加入适当的风险控制。
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>
/// Strategy that enters when price breaks the Triangular Moving Average by configurable offsets.
/// </summary>
public class TmaBreakoutStrategy : Strategy
{
private readonly StrategyParam<int> _length;
private readonly StrategyParam<decimal> _upLevel;
private readonly StrategyParam<decimal> _downLevel;
private readonly StrategyParam<DataType> _candleType;
private decimal? _prevTma;
private decimal? _prevClose;
/// <summary>
/// Period for the Triangular Moving Average.
/// </summary>
public int Length
{
get => _length.Value;
set => _length.Value = value;
}
/// <summary>
/// Offset above the TMA to trigger a long entry.
/// </summary>
public decimal UpLevel
{
get => _upLevel.Value;
set => _upLevel.Value = value;
}
/// <summary>
/// Offset below the TMA to trigger a short entry.
/// </summary>
public decimal DownLevel
{
get => _downLevel.Value;
set => _downLevel.Value = value;
}
/// <summary>
/// Candle type.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Initialize the TMA breakout strategy.
/// </summary>
public TmaBreakoutStrategy()
{
_length = Param(nameof(Length), 30)
.SetDisplay("TMA Length", "Period for the Triangular Moving Average", "Parameters")
.SetOptimize(10, 60, 10);
_upLevel = Param(nameof(UpLevel), 300m)
.SetDisplay("Upper Level", "Offset above TMA in price units", "Parameters")
.SetOptimize(100m, 500m, 100m);
_downLevel = Param(nameof(DownLevel), 300m)
.SetDisplay("Lower Level", "Offset below TMA in price units", "Parameters")
.SetOptimize(100m, 500m, 100m);
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Type of candles to use", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevTma = _prevClose = null;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var tma = new ExponentialMovingAverage { Length = Length };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(tma, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, tma);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal tmaValue)
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
return;
var prevTma = _prevTma;
var prevClose = _prevClose;
if (prevTma is null || prevClose is null)
{
_prevTma = tmaValue;
_prevClose = candle.ClosePrice;
return;
}
var signalUp = prevClose > prevTma + UpLevel;
var signalDn = prevClose < prevTma - DownLevel;
if (signalUp && Position <= 0)
{
if (Position < 0)
BuyMarket();
BuyMarket();
}
else if (signalDn && Position >= 0)
{
if (Position > 0)
SellMarket();
SellMarket();
}
_prevTma = tmaValue;
_prevClose = candle.ClosePrice;
}
}
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.Indicators import ExponentialMovingAverage
from StockSharp.Algo.Strategies import Strategy
class tma_breakout_strategy(Strategy):
def __init__(self):
super(tma_breakout_strategy, self).__init__()
self._length = self.Param("Length", 30) \
.SetDisplay("TMA Length", "Period for the Triangular Moving Average", "Parameters")
self._up_level = self.Param("UpLevel", 300.0) \
.SetDisplay("Upper Level", "Offset above TMA in price units", "Parameters")
self._down_level = self.Param("DownLevel", 300.0) \
.SetDisplay("Lower Level", "Offset below TMA in price units", "Parameters")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Type of candles to use", "General")
self._prev_tma = None
self._prev_close = None
@property
def length(self):
return self._length.Value
@property
def up_level(self):
return self._up_level.Value
@property
def down_level(self):
return self._down_level.Value
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(tma_breakout_strategy, self).OnReseted()
self._prev_tma = None
self._prev_close = None
def OnStarted2(self, time):
super(tma_breakout_strategy, self).OnStarted2(time)
tma = ExponentialMovingAverage()
tma.Length = self.length
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(tma, self.process_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, tma)
self.DrawOwnTrades(area)
def process_candle(self, candle, tma_value):
if candle.State != CandleStates.Finished:
return
tma_val = float(tma_value)
close = float(candle.ClosePrice)
if self._prev_tma is None or self._prev_close is None:
self._prev_tma = tma_val
self._prev_close = close
return
signal_up = self._prev_close > self._prev_tma + float(self.up_level)
signal_dn = self._prev_close < self._prev_tma - float(self.down_level)
if signal_up and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
elif signal_dn and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
self._prev_tma = tma_val
self._prev_close = close
def CreateClone(self):
return tma_breakout_strategy()