Blonde Trader é uma estratégia de trading em grade convertida do MQL. Ela busca movimentos de preço afastando-se de extremos recentes e abre posições com uma grade de ordens pendentes.
Conceito
Calcular o máximo mais alto e o mínimo mais baixo nas últimas Period X velas.
Se o preço atual estiver abaixo da máxima recente por mais de Limit ticks, abrir uma posição comprada e colocar uma série de ordens buy limit formando uma grade.
Se o preço atual estiver acima da mínima recente por mais de Limit ticks, abrir uma posição vendida e colocar uma série de ordens sell limit formando uma grade.
Fechar todas as posições quando o lucro acumulado atingir Amount.
Opcionalmente, após o preço mover LockDown ticks em lucro, uma ordem stop é colocada no nível de equilíbrio para proteger a posição.
Parâmetros
Nome
Descrição
PeriodX
Período de retrocesso para a máxima mais alta e a mínima mais baixa.
Limit
Distância mínima em ticks do preço atual até um extremo.
Grid
Passo em ticks entre as ordens pendentes da grade.
Amount
Meta de lucro na moeda da conta.
LockDown
Distância em ticks para mover o stop ao ponto de equilíbrio.
CandleType
Tipo de velas usadas para análise.
Indicadores
Highest – rastreia a máxima mais alta durante o período de retrocesso.
Lowest – rastreia a mínima mais baixa durante o período de retrocesso.
Lógica de Ordens
Quando um setup comprado aparece:
Comprar a mercado com o volume padrão da estratégia.
Colocar quatro ordens buy limit adicionais abaixo da entrada, cada uma separada por Grid ticks e dobrando o volume.
Quando um setup vendido aparece:
Vender a mercado com o volume padrão da estratégia.
Colocar quatro ordens sell limit adicionais acima da entrada com as mesmas regras de grade e duplicação de volume.
Se PnL atingir Amount, todas as posições abertas e ordens pendentes são fechadas.
Se LockDown for maior que zero e o preço tiver movido o número especificado de ticks a favor da posição, uma ordem stop protetora é colocada um tick além do preço de entrada.
Notas
Esta estratégia demonstra a lógica básica de trading em grade. Usa apenas recursos de API de alto nível: SubscribeCandles, vinculação de indicadores e auxiliares de ordens simples como BuyMarket, SellLimit e SellStop.
using System;
using System.Collections.Generic;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Blonde Trader strategy. Buys when price pulls back from recent high,
/// sells when price bounces from recent low. Uses Highest/Lowest indicators.
/// </summary>
public class BlondeTraderStrategy : Strategy
{
private readonly StrategyParam<int> _lookback;
private readonly StrategyParam<decimal> _threshold;
private readonly StrategyParam<DataType> _candleType;
private decimal _entryPrice;
public int Lookback { get => _lookback.Value; set => _lookback.Value = value; }
public decimal Threshold { get => _threshold.Value; set => _threshold.Value = value; }
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public BlondeTraderStrategy()
{
_lookback = Param(nameof(Lookback), 20)
.SetGreaterThanZero()
.SetDisplay("Lookback", "Period for Highest/Lowest", "General");
_threshold = Param(nameof(Threshold), 0.002m)
.SetDisplay("Threshold", "Min distance ratio from extreme", "General");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Type of candles", "General");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
=> [(Security, CandleType)];
protected override void OnReseted()
{
base.OnReseted();
_entryPrice = 0;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var highest = new Highest { Length = Lookback };
var lowest = new Lowest { Length = Lookback };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(highest, lowest, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal high, decimal low)
{
if (candle.State != CandleStates.Finished)
return;
var price = candle.ClosePrice;
var range = high - low;
if (range <= 0 || high == 0)
return;
var distFromHigh = (high - price) / high;
var distFromLow = (price - low) / price;
// Buy signal: price pulled back from high by at least threshold
if (distFromHigh > Threshold && Position <= 0)
{
BuyMarket();
_entryPrice = price;
}
// Sell signal: price bounced up from low by at least threshold
else if (distFromLow > Threshold && Position >= 0)
{
SellMarket();
_entryPrice = price;
}
}
}
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 Highest, Lowest
from StockSharp.Algo.Strategies import Strategy
class blonde_trader_strategy(Strategy):
def __init__(self):
super(blonde_trader_strategy, self).__init__()
self._lookback = self.Param("Lookback", 20) \
.SetDisplay("Lookback", "Period for Highest/Lowest", "General")
self._threshold = self.Param("Threshold", 0.002) \
.SetDisplay("Threshold", "Min distance ratio from extreme", "General")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Type of candles", "General")
self._entry_price = 0.0
@property
def lookback(self):
return self._lookback.Value
@property
def threshold(self):
return self._threshold.Value
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(blonde_trader_strategy, self).OnReseted()
self._entry_price = 0.0
def OnStarted2(self, time):
super(blonde_trader_strategy, self).OnStarted2(time)
highest = Highest()
highest.Length = self.lookback
lowest = Lowest()
lowest.Length = self.lookback
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(highest, lowest, self.OnProcess).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawOwnTrades(area)
def OnProcess(self, candle, high, low):
if candle.State != CandleStates.Finished:
return
price = float(candle.ClosePrice)
high_val = float(high)
low_val = float(low)
range_val = high_val - low_val
if range_val <= 0 or high_val == 0:
return
dist_from_high = (high_val - price) / high_val
dist_from_low = (price - low_val) / price
if dist_from_high > self.threshold and self.Position <= 0:
self.BuyMarket()
self._entry_price = price
elif dist_from_low > self.threshold and self.Position >= 0:
self.SellMarket()
self._entry_price = price
def CreateClone(self):
return blonde_trader_strategy()