Przejdź do treści

Koduj strategie wielookresowe

Często zautomatyzowane strategie muszą uwzględniać informacje z różnych okresów przed podjęciem decyzji handlowej. Na szczęście cTrader zapewnia wiele narzędzi, które umożliwiają algorytmom łatwy dostęp do danych z wielu okresów. W tym filmie i odpowiadającym mu artykule wyjaśnimy, jak możesz użyć tych narzędzi do stworzenia skutecznego cBota.

Zadeklaruj parametry cBota

Zaczniemy od zadeklarowania niezbędnych parametrów dla średniej ruchomej. Będziemy potrzebować okresu, przedziału czasowego i typu średniej ruchomej.

1
2
3
4
5
6
7
8
[Parameter("MA 1 Period", DefaultValue = 14, Group = "Moving Averages")]
        public int MA1Period { get; set; }

[Parameter("MA 1 Timeframe", DefaultValue = "Hour", Group = "Moving Averages")]
public TimeFrame MA1Timeframe { get; set; }

[Parameter("MA 1 Type", Group = "Moving Averages")]
public MovingAverageType MA1Type { get; set; }

Następnie możemy zdefiniować średnią ruchomą.

1
private MovingAverage _ma1;

Możemy zainicjować średnią ruchomą w metodzie OnStart(). Użyjemy metody MarketData.GetBars(), aby uzyskać słupki pierwszej średniej ruchomej i przekazać je do konstruktora wskaźnika. Metoda GetBars() jest przydatna do uzyskiwania danych słupkowych dla dowolnego okresu i dowolnego symbolu, którego potrzebujesz.

1
_ma1 = Indicators.MovingAverage(MarketData.GetBars(MA1Timeframe).ClosePrices, MA1Period, MA1Type);

Powtórzymy proces dla pozostałych dwóch średnich ruchomych. Możesz po prostu skopiować i wkleić poniższy kod, aby kontynuować.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
Parameter("MA 1 Period", DefaultValue = 14, Group = "Moving Averages")]
public int MA1Period { get; set; }

[Parameter("MA 1 Timeframe", DefaultValue = "Hour", Group = "Moving Averages")]
public TimeFrame MA1Timeframe { get; set; }

[Parameter("MA 1 Type", Group = "Moving Averages")]
public MovingAverageType MA1Type { get; set; }

[Parameter("MA 2 Period", DefaultValue = 14, Group = "Moving Averages")]
public int MA2Period { get; set; }

[Parameter("MA 2 Timeframe", DefaultValue = "Hour2", Group = "Moving Averages")]
public TimeFrame MA2Timeframe { get; set; }

[Parameter("MA 2 Type", Group = "Moving Averages")]
public MovingAverageType MA2Type { get; set; }

[Parameter("MA 3 Period", DefaultValue = 14, Group = "Moving Averages")]
public int MA3Period { get; set; }

[Parameter("MA 3 Timeframe", DefaultValue = "Hour4", Group = "Moving Averages")]
public TimeFrame MA3Timeframe { get; set; }

[Parameter("MA 3 Type", Group = "Moving Averages")]
public MovingAverageType MA3Type { get; set; }

private MovingAverage _ma1;
private MovingAverage _ma2;
private MovingAverage _ma3;

protected override void OnStart()
{
    _ma1 = Indicators.MovingAverage(MarketData.GetBars(MA1Timeframe).ClosePrices, MA1Period, MA1Type);
    _ma2 = Indicators.MovingAverage(MarketData.GetBars(MA2Timeframe).ClosePrices, MA2Period, MA2Type);
    _ma3 = Indicators.MovingAverage(MarketData.GetBars(MA3Timeframe).ClosePrices, MA3Period, MA3Type);
}

Zaimplementuj logikę handlową

W tym momencie możemy zaimplementować logikę handlową. Nasza strategia będzie utrzymywać pozycję kupna, gdy wszystkie średnie ruchome rosną, oraz pozycję sprzedaży, gdy średnie ruchome spadają. Oto kod dla całej logiki strony kupna.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
if (_ma1.Result.IsRising() && _ma2.Result.IsRising() && _ma3.Result.IsRising())
{
    if (Positions.Count(p => p.SymbolName == SymbolName && p.TradeType == TradeType.Buy) == 0)
        ExecuteMarketOrder(TradeType.Buy, SymbolName, 100000);
}
else
{
    foreach (var position in Positions.Where(p => p.SymbolName == SymbolName && p.TradeType == TradeType.Buy))
    {
        position.Close();
    }
}

A oto kod dla logiki strony sprzedaży.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
if (_ma1.Result.IsFalling() && _ma2.Result.IsFalling() && _ma3.Result.IsFalling())
{
    if (Positions.Count(p => p.SymbolName == SymbolName && p.TradeType == TradeType.Sell) == 0)
        ExecuteMarketOrder(TradeType.Sell, SymbolName, 100000);
}
else
{
    foreach (var position in Positions.Where(p => p.SymbolName == SymbolName && p.TradeType == TradeType.Sell))
    {
        position.Close();
    }
}

Przetestuj strategię wielookresową

Na koniec powinniśmy przetestować naszego nowego cBota. Możemy zobaczyć, że cBot otwiera pozycje, gdy średnie ruchome są zsynchronizowane w tym samym kierunku i pozostaje poza rynkiem, gdy każdy wskaźnik wskazuje inny kierunek.