Przejdź do treści

Przykłady kodu cBotów

Ta strona zawiera kilka przykładów kodu w Pythonie i C# do tworzenia botów handlowych i rozwijania algorytmów. Należy pamiętać, że żaden z wymienionych poniżej cBotów nie gwarantuje żadnych zwrotów finansowych. Przed wdrożeniem jakichkolwiek instancji na koncie rzeczywistym należy przeprowadzić backtesting i dostosować cBoty.

Repozytoria przykładów cBotów

Kompleksowe przykłady kodu cBotów, w tym gotowe do uruchomienia szablony dla różnych zautomatyzowanych strategii i stylów handlu, są dostępne w oddzielnych repozytoriach Python i C# w GitHub.

Operacje synchroniczne

Wszystkie cBoty w tej sekcji wykonują swoje operacje synchronicznie.

Wykonuj zlecenia rynkowe

  • Prosty cBot wykonujący udane operacje

    Poniższy bot handlowy tworzy zlecenie rynkowe przy uruchomieniu i zapisuje wynik w zmiennej result.

    Jeśli wykonanie zlecenia zakończy się sukcesem, cena otwarcia zostaje wyświetlona w dzienniku.

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    [Robot()]
    public class Sample_cBot : Robot
    {
        protected override void OnStart()
        {
            var result = ExecuteMarketOrder(TradeType.Buy, SymbolName, 10000);
    
            if (result.IsSuccessful)
            {
                var position = result.Position;
                Print("Position entry price is {0}", position.EntryPrice);
            }
        }
    }
    
    1
    2
    3
    4
    5
    6
    7
    class Sample_cBot():
        def on_start(self):
            result = api.ExecuteMarketOrder(TradeType.Buy, api.SymbolName, 10000)
    
            if result.IsSuccessful:
                position = result.Position
                api.Print(f"Position entry price is {position.EntryPrice}")
    

    Wynik dziennika

    • cBot "New cBot" został pomyślnie uruchomiony dla EURUSD, h1.
    • Wykonywanie zlecenia rynkowego kupna 10000 EURUSD
    • Wykonywanie zlecenia rynkowego kupna 10000 EURUSD ZAKOŃCZONE SUKCESEM, Pozycja PID14576001
    • Cena otwarcia pozycji wynosi 1.19067
  • Prosty cBot z konfigurowalnymi parametrami

    Podczas deklarowania różnych właściwości cBota możesz przekształcić je w konfigurowalne parametry za pomocą deklaracji [Parameter()]. Gdy uruchamiana jest nowa instancja Twojego cBota, Ty (lub inni użytkownicy) będziecie mogli przypisać niestandardowe wartości do nich.

    Rozważ poniższy przykład.

    1
    2
    [Parameter("SMA Period", DefaultValue = 14)]
    public int SmaPeriod { get; set; }
    

    Uwaga

    cBoty w Pythonie używają konfigurowalnych parametrów zadeklarowanych w ich plikach .cs.

    1
    2
    [Parameter("SMA Period", DefaultValue = 14)]
    public int SmaPeriod { get; set; }
    

    W powyższym przykładzie definiujemy następujące cechy:

    • Nazwę parametru. Następnie pojawi się ona w interfejsie użytkownika cTrader ("SMA Period").
    • Wartość domyślną parametru, która będzie stosowana do wszystkich nowych instancji, chyba że zostanie zmieniona przez użytkowników (DefaultValue = 14).

    W poniższym kodzie pokazujemy, jak właściwość SmaPeriod może być używana w rzeczywistym bocie handlowym.

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    [Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
    public class SamplecBotReferenceSMA : Robot
    {
        [Parameter("Source")]
        public DataSeries Source { get; set; }
    
        [Parameter("SMA Period", DefaultValue = 14)]
        public int SmaPeriod { get; set; }
    
        private SampleSMA sma;
    
        protected override void OnStart()
        {
            sma = Indicators.GetIndicator<SampleSMA>(Source, SmaPeriod);
        }
    
        protected override void OnTick()
        {
            Print("{0}", sma.Result.LastValue);
        }
    }
    

    Uwaga

    cBoty w Pythonie używają konfigurowalnych parametrów zadeklarowanych w ich plikach .cs.

    1
    2
    3
    4
    5
    6
    class Sample_cBot():
        def on_start(self):
            self.sma = api.Indicators.GetIndicator<SampleSMA>(api.Source, api.SmaPeriod)
    
        def on_tick(self):
            api.Print(f"{self.sma.Result.LastValue}")
    

    Nasz bot pobiera konfigurowalną właściwość SmaPeriod i przy uruchomieniu przekazuje jej wartość do metody Indicators.GetIndicator<SampleSMA>(). Ta metoda zwraca wartość prostej średniej ruchomej dla określonego okresu.

    Podczas tworzenia instancji cBota wszystkie regulowane parametry można skonfigurować w oknie Dodaj instancję.

    Po uruchomieniu cBot informuje nas o tym, jaka była ostatnia wartość prostej średniej ruchomej przy każdym ticku.

    Wynik dziennika

    • Uruchomiono instancję cBota [Sample cBot Reference SMA, EURUSD, h1].
    • 0.975685714285714
    • 0.975681428571429
    • 0.97568
    • Instancja cBota [Sample cBot Reference SMA, EURUSD, h1] zatrzymana przez użytkownika.
  • Wykonaj zlecenie rynkowe z większą liczbą argumentów

    W poprzednim przykładzie przekazaliśmy minimalną możliwą liczbę argumentów do metody ExecuteMarketOrder(). Były to typ transakcji (TradeType.Buy), symbol (Symbol) i wolumen (-1).

    Metoda ExecuteMarketOrder() może być wywoływana z dodatkowymi argumentami, takimi jak Label, StopLoss, TakeProfit i Comment. Poniższy przykład określa etykietę ("order 1"), mechanizm ochrony Stop loss (10) i poziom Take profit (10).

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    [Robot(TimeZone = TimeZones.UTC)]
    public class Sample_cBot : Robot
    {
        protected override void OnStart()
        {
            var result = ExecuteMarketOrder(TradeType.Buy, SymbolName, 10000, "order 1", 10, 10);
    
            if (result.IsSuccessful)
            {
                var position = result.Position;
                Print("Position entry price is {0}", position.EntryPrice);
                Print("Position SL price is {0}", position.StopLoss);
            }
        }
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    class Sample_cBot():
        def on_start(self):
            result = api.ExecuteMarketOrder(TradeType.Buy, api.SymbolName, 10000, "order 1", 10, 10)
    
            if result.IsSuccessful:
                position = result.Position
                api.Print(f"Position entry price is {position.EntryPrice}")
                api.Print(f"Position SL price is {position.StopLoss}")
    

    Wynik dziennika

    • cBot "New cBot" został pomyślnie uruchomiony dla EURUSD, h1.
    • Wykonywanie zlecenia rynkowego kupna 10000 EURUSD (SL: 10, TP: 10)
    • Wykonywanie zlecenia rynkowego kupna 10000 EURUSD (SL: 10, TP: 10) ZAKOŃCZONE SUKCESEM, Pozycja PID14576098
    • Cena otwarcia pozycji wynosi 1.1896
    • Cena SL pozycji wynosi 1.1886

Modyfikacja pozycji

W poniższym przykładzie dodajemy tylko wartość Take profit (10) podczas wykonywania zlecenia. Następnie modyfikujemy pozycję, aby dodać Stop loss.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
[Robot()]
public class SamplecBbot : Robot
{
    protected override void OnStart()
    {
        var result = ExecuteMarketOrder(TradeType.Buy, SymbolName, 10000,
                                "order 1", null, 10);
        if (result.IsSuccessful)
        {
            var position = result.Position;
            Print("Position SL price is {0}", position.StopLoss);

            var stopLoss = position.EntryPrice - 10*Symbol.PipSize;
            ModifyPosition(position, stopLoss, position.TakeProfit);

            Print("New Position SL price is {0}", position.StopLoss);

        }
    }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
class Sample_cBot():
    def on_start(self):
        result = api.ExecuteMarketOrder(TradeType.Buy, api.SymbolName, 10000, "order 1", None, 10)

        if result.IsSuccessful:
            position = result.Position
            api.Print(f"Position SL price is {position.StopLoss}")
            stopLoss = position.EntryPrice - 10 * api.Symbol.PipSize
            api.ModifyPosition(position, stopLoss, position.TakeProfit)
            api.Print(f"New Position SL price is {position.StopLoss}")

Wynik dziennika

  • cBot "New cBot" został pomyślnie uruchomiony dla EURUSD, h1.
  • Wykonywanie zlecenia rynkowego kupna 10000 EURUSD (TP: 10)
  • Wykonywanie zlecenia rynkowego kupna 10000 EURUSD (TP: 10) ZAKOŃCZONE SUKCESEM, Pozycja PID14576161
  • Cena SL pozycji wynosi null
  • Modyfikowanie pozycji PID14576161 (SL: 1.18744, TP: 1.18944)
  • Modyfikowanie pozycji PID14576161 (SL: 1.18744, TP: 1.18944) ZAKOŃCZONE SUKCESEM, Pozycja PID14576161
  • Nowa cena SL pozycji wynosi 1.18744

Zamknij pozycję

  • Wykonaj pełne zamknięcie

    Poniższy przykład kodu składa zlecenie rynkowe. Jeśli zysk brutto wynikowej pozycji przekracza określoną wartość (null && position.GrossProfit > 10), zostaje ona zamknięta.

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    [Robot()]
    public class Sample_cBot : Robot
    {
        protected override void OnStart()
        {
            ExecuteMarketOrder(TradeType.Buy, SymbolName, 10000, "myLabel");
        }
    
        protected override void OnTick()
        {
            var position = Positions.Find("myLabel");
            if (position != null && position.GrossProfit > 10)
            {
                ClosePosition(position);
                Stop();
            }
        }
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    class Sample_cBot():
        def on_start(self):
            api.ExecuteMarketOrder(TradeType.Buy, api.SymbolName, 10000, "myLabel")
    
        def on_tick(self):
            position = api.Positions.Find("myLabel")
            if position is not None and position.GrossProfit > 10:
                api.ClosePosition(position)
                api.Stop()
    

    Wynik dziennika

    • cBot "New cBot" został pomyślnie uruchomiony dla EURUSD, h1.
    • Wykonywanie zlecenia rynkowego kupna 10000 EURUSD
    • Wykonywanie zlecenia rynkowego kupna 10000 EURUSD ZAKOŃCZONE SUKCESEM, Pozycja PID14576180
  • Wykonaj częściowe zamknięcie

    Zmodyfikujemy poprzedni przykład, aby utworzyć dwa zlecenia rynkowe z tymi samymi etykietami ("myLabel"). Przy każdym nowym słupku nasz bot handlowy zamknie dokładnie połowę jednego z tych zleceń, ale tylko wtedy, gdy jego wolumen będzie równy lub większy niż 20 000.

    Używamy również metody Positions.FindAll(). Zwraca ona listę pozycji, przez które możemy iterować.

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    [Robot()]
    public class Sample_cBot : Robot
    {
        protected override void OnStart()
        {
            ExecuteMarketOrder(TradeType.Buy, SymbolName, 20000, "myLabel");
            ExecuteMarketOrder(TradeType.Buy, SymbolName, 30000, "myLabel");
        }
    
        protected override void OnBar()
        {
            var positions = Positions.FindAll("myLabel", SymbolName, TradeType.Buy);
    
            foreach (var position in positions)
            {
                if (position.VolumeInUnits >= 20000)
                {
                    ClosePosition(position, 15000);
                }
            }
        }
    }
    
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    class Sample_cBot():
        def on_start(self):
            api.ExecuteMarketOrder(TradeType.Buy, api.SymbolName, 20000, "myLabel")
            api.ExecuteMarketOrder(TradeType.Buy, api.SymbolName, 30000, "myLabel")
    
        def on_tick(self):
            positions = api.Positions.FindAll("myLabel", api.SymbolName, TradeType.Buy)
            for position in positions:
                if position.VolumeInUnits >= 20000:
                    api.ClosePosition(position, 15000)
    

    Wynik dziennika

    • cBot "New cBot" został pomyślnie uruchomiony dla EURUSD, h1.
    • Wykonywanie zlecenia rynkowego kupna 20000 EURUSD
    • Wykonywanie zlecenia rynkowego kupna 20000 EURUSD ZAKOŃCZONE SUKCESEM, Pozycja PID14579299
    • Wykonywanie zlecenia rynkowego kupna 30000 EURUSD
    • Wykonywanie zlecenia rynkowego kupna 30000 EURUSD ZAKOŃCZONE SUKCESEM, Pozycja PID14579300

Twórz zlecenia oczekujące

  • Twórz zlecenia z limitem i zlecenia stop

    Zlecenia z limitem i zlecenia stop to zlecenia oczekujące; mimo to są tworzone podobnie do zleceń rynkowych. Jednak podczas tworzenia zleceń z limitem i zleceń stop musisz również określić ich cenę docelową i nie ma dopuszczalnego poślizgu.

    Ten cBot tworzy dwa zlecenia z limitem i zlecenie stop. Następnie iteruje przez zlecenia i wyświetla ich etykiety oraz identyfikatory w dzienniku.

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    [Robot()]
    public class Sample_cBot : Robot
    {
        protected override void OnStart()
        {
            PlaceLimitOrder(TradeType.Buy, SymbolName, 10000, Symbol.Bid, "myLimitOrder");
            PlaceLimitOrder(TradeType.Buy, SymbolName, 20000, Symbol.Bid-2*Symbol.PipSize,
                    "myLimitOrder");
            PlaceStopOrder(TradeType.Buy, SymbolName, 10000, Symbol.Ask, "myStopOrder");
    
            foreach (var pendingOrder in PendingOrders)
            {
                Print("Order placed with label {0}, id {1}", pendingOrder.Label, pendingOrder.Id);
            }
        }
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    class Sample_cBot():
        def on_start(self):
            api.PlaceLimitOrder(TradeType.Buy, api.SymbolName, 10000, api.Symbol.Bid, "myLimitOrder")
            api.PlaceLimitOrder(TradeType.Buy, api.SymbolName, 20000, api.Symbol.Bid - 2 * api.Symbol.PipSize, "myLimitOrder")
            api.PlaceStopOrder(TradeType.Buy, api.SymbolName, 10000, api.Symbol.Ask, "myStopOrder")
    
            for pendingOrder in api.PendingOrders:
                Print(f"Order placed with label {pendingOrder.Label}, id {pendingOrder.Id}")
    

    Wynik dziennika

    • cBot "New cBot" został pomyślnie uruchomiony dla EURUSD, h1.
    • Składanie zlecenia z limitem kupna 10000 EURUSD (Cena: 1.19036)
    • Składanie zlecenia z limitem kupna 10000 EURUSD (Cena: 1.19036) POWIODŁO SIĘ, PendingOrder OID25220794
    • Składanie zlecenia z limitem kupna 20000 EURUSD (Cena: 1.19017)
    • Składanie zlecenia z limitem kupna 20000 EURUSD (Cena: 1.19017) POWIODŁO SIĘ, PendingOrder OID25220795
    • Składanie zlecenia Stop kupna 10000 EURUSD (Cena: 1.19040)
    • Składanie zlecenia Stop kupna 10000 EURUSD (Cena: 1.19040) POWIODŁO SIĘ, PendingOrder OID25220796
    • Złożono zlecenie z etykietą myLimitOrder, id 25220794
    • Złożono zlecenie z etykietą myLimitOrder, id 25220795
    • Złożono zlecenie z etykietą myStopOrder, id 25220796
  • Tworzenie zleceń oczekujących z większą liczbą parametrów

    Podobnie jak w przypadku zleceń rynkowych, możesz również określić etykietę zlecenia, różne mechanizmy ochrony, datę wygaśnięcia zlecenia i dodać komentarz.

     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
    [Robot()]
    public class Sample_cBot : Robot
    {
        protected override void OnStart()
        {
            var midnight = Server.Time.AddDays(1).Date;
    
            PlaceLimitOrder(TradeType.Buy, SymbolName, 10000, Symbol.Bid, "mySample_cBot", 10, null, midnight, "First");
    
            PlaceStopOrder(TradeType.Buy, SymbolName, 10000, Symbol.Ask, "mySample_cBot", 10, 10, null, "Second");
    
            foreach (var order in PendingOrders)
            {
                var sl = order.StopLoss == null ? "" : "SL: " + order.StopLoss;
                var tp = order.TakeProfit == null ? "" : " TP: " + order.TakeProfit;
    
                var text = string.Format("{0} {1}", sl, tp);
    
                if (order.OrderType == PendingOrderType.Limit)
                    Print(order.Comment + " Limit Order " + text);
                else
                    Print(order.Comment + " Stop Order " + text);
            }
        }
    }
    
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    class Sample_cBot():
        def on_start(self):
            midnight = api.Server.Time.AddDays(1).Date
    
            api.PlaceLimitOrder(TradeType.Buy, api.SymbolName, 10000, api.Symbol.Bid, "mySample_cBot", 10, None, midnight, "First")
            api.PlaceStopOrder(TradeType.Buy, api.SymbolName, 10000, api.Symbol.Ask, "mySample_cBot", 10, 10, None, "Second")
    
            for order in api.PendingOrders:
                sl = "" if order.StopLoss is None else f"SL: {order.StopLoss}"
                tp = "" if order.TakeProfit is None else f"TP: {order.TakeProfit}"
    
                api.Print(f"{order.Comment} {order.OrderType} Order {sl} {tp}")
    

    Wynik dziennika

    • cBot "New cBot" został pomyślnie uruchomiony dla EURUSD, h1.
    • Składanie zlecenia z limitem kupna 10000 EURUSD (Cena: 1.19049, SL: 10, ExpireTime: 12/05/2018 00:00:00)
    • Składanie zlecenia z limitem kupna 10000 EURUSD (Cena: 1.19049, SL: 10, ExpireTime: 12/05/2018 00:00:00) POWIODŁO SIĘ, PendingOrder OID25220807
    • Składanie zlecenia Stop kupna 10000 EURUSD (Cena: 1.19053, SL: 10, TP: 10)
    • Składanie zlecenia Stop kupna 10000 EURUSD (Cena: 1.19053, SL: 10, TP: 10) POWIODŁO SIĘ, PendingOrder OID25220808
    • Zlecenie z limitem
    • Pierwsze zlecenie z limitem SL: 1.18949
    • Drugie zlecenie Stop SL: 1.18953 TP: 1.19153

Modyfikuj zlecenia oczekujące

Możliwa jest modyfikacja kilku cech zleceń oczekujących.

Poniższy przykład pokazuje, jak zmodyfikować cenę docelową, poziomy ochrony lub datę i godzinę wygaśnięcia zlecenia oczekującego.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
[Robot()]
public class Sample_cBot : Robot
{
    protected override void OnStart()
    {
        var price = Symbol.Ask + 10 * Symbol.PipSize;
        var expiry = Server.Time.AddHours(12);
        PlaceStopOrder(TradeType.Buy, SymbolName, 10000, price, "myLabel", 10, 10, expiry);
    }

    protected override void OnBar()
    {
        foreach (var order in PendingOrders)
        {
            if (order.Label == "myLabel")
            {
                double newPrice = Symbol.Ask + 5 * Symbol.PipSize;
                ModifyPendingOrder(order, newPrice, order.StopLossPips,
                                                            order.TakeProfitPips, order.ExpirationTime);
            }
        }
    }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
class Sample_cBot():
    def on_start(self):
        price = api.Symbol.Ask + 10 * api.Symbol.PipSize
        expiry = Server.Time.AddHours(12)

        api.PlaceStopOrder(TradeType.Buy, api.SymbolName, 10000, price, "myLabel", 10, 10, expiry)

    def on_bar(self):
        for order in api.PendingOrders:
            if order.Label == "myLabel":
                newPrice = api.Symbol.Ask + 5 * api.Symbol.PipSize
                api.ModifyPendingOrder(order, newPrice, order.StopLossPips, order.TakeProfitPips, order.ExpirationTime)

Wynik dziennika

  • cBot "New cBot" został pomyślnie uruchomiony dla EURUSD, h1.
  • Składanie zlecenia Stop kupna 10000 EURUSD (Cena: 1.19254, SL: 10, TP: 10, ExpireTime: 11/05/2018 20:07:25)
  • Składanie zlecenia Stop kupna 10000 EURUSD (Cena: 1.19254, SL: 10, TP: 10, ExpireTime: 11/05/2018 20:07:25) POWIODŁO SIĘ, PendingOrder OID25220877

Anuluj zlecenia oczekujące

Składnia anulowania zlecenia to CancelPendingOrder(order), gdzie order jest typu PendingOrder.

Poniższy przykład pokazuje anulowanie wszystkich zleceń z etykietą "myLabel".

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
[Robot()]
public class Sample_cBot : Robot
{
    protected override void OnTick()
    {
        foreach (var order in PendingOrders)
        {
            if (order.Label == "myLabel")
            {
                CancelPendingOrder(order);
            }
        }
    }
}
1
2
3
4
5
class Sample_cBot():
    def on_tick(self):
        for order in api.PendingOrders:
            if order.Label == "myLabel":
                api.CancelPendingOrder(order)

Zdarzenia pozycji

Możliwa jest subskrypcja zdarzeń związanych z różnymi operacjami handlowymi. Na przykład, aby sprawdzić, czy pozycja jest otwarta, subskrybujemy zdarzenie, które jest wywoływane dla wszystkich obiektów Position przy otwarciu.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
[Robot()]
public class Sample_cBot : Robot
{
    protected override void OnStart()
    {
        Positions.Opened += PositionsOnOpened;
        ExecuteMarketOrder(TradeType.Buy, Symbol, 10000, "myLabel", 10, 10);
    }

    private void PositionsOnOpened(PositionOpenedEventArgs args)
    {
        var pos = args.Position;
        Print("Position opened at {0}", pos.EntryPrice);
    }
}
1
2
3
4
5
6
7
8
class Sample_cBot():
    def on_start(self):
        api.Positions.Opened += self.on_position_opened
        api.ExecuteMarketOrder(TradeType.Buy, api.Symbol, 10000, "myLabel", 10, 10)

    def on_position_opened(self, args):
        pos = args.Position
        api.Print(f"Position opened at {pos.EntryPrice}")

Wynik dziennika

  • cBot "New cBot" został pomyślnie uruchomiony dla EURUSD, h1.
  • Realizacja zlecenia rynkowego kupna 10000 EURUSD (SL: 10, TP: 10)
  • Realizacja zlecenia rynkowego kupna 10000 EURUSD (SL: 10, TP: 10) POWIODŁA SIĘ, Position PID14579468
  • Pozycja otwarta po 1.19224

Podobnie możliwa jest subskrypcja zdarzeń, które są wywoływane za każdym razem, gdy pozycja jest zamykana.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
[Robot()]
public class Sample_cBot : Robot
{
    protected override void OnStart()
    {
        Positions.Closed += PositionsOnClosed;
        ExecuteMarketOrder(TradeType.Buy, Symbol, 10000, "myLabel", 10, 10);
    }

    protected override void OnBar()
    {
        var position = Positions.Find("myLabel");
        if (position != null)
            ClosePosition(position);
    }

    private void PositionsOnClosed(PositionClosedEventArgs args)
    {
        var pos = args.Position;
        Print("Position closed with {0} profit", pos.GrossProfit);
    }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
class Sample_cBot():
    def on_start(self):
        api.Positions.Closed += self.on_position_closed
        api.ExecuteMarketOrder(TradeType.Buy, api.Symbol, 10000, "myLabel", 10, 10)

    def on_bar(self):
        position = api.Positions.Find("myLabel")

        if position is not None:
            api.ClosePosition(position);            

    def on_position_closed(self, args):
        pos = args.Position
        api.Print(f"Position closed with {pos.GrossProfit} profit")

Wynik dziennika

  • cBot "New cBot" został pomyślnie uruchomiony dla EURUSD, h1.
  • Realizacja zlecenia rynkowego kupna 10000 EURUSD (SL: 10, TP: 10)
  • Realizacja zlecenia rynkowego kupna 10000 EURUSD (SL: 10, TP: 10) POWIODŁA SIĘ, Position PID14579479
  • Zamykanie pozycji PID14579299
  • Zamykanie pozycji PID14579299 POWIODŁO SIĘ, Position PID14579299
  • Pozycja zamknięta z zyskiem 20.64

Konwersja współrzędnych

Poniższy cBot umożliwia użytkownikom składanie zleceń z limitem w odpowiednim kierunku poprzez kliknięcie prawym przyciskiem myszy na wykresie. Osiąga to poprzez konwersję współrzędnych Y myszy na współrzędne Y wykresu (które w przypadku symboli odpowiadają cenom symboli).

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
[Robot(AccessRights = AccessRights.None)]
public class CoordinatesConverter : Robot
{
    protected override void OnStart()
    {
        Chart.MouseUp += Chart_MouseUp;
    }

    private void Chart_MouseUp(ChartMouseEventArgs obj)
    {
        var desiredPrice = Chart.YToYValue(obj.MouseY);
        var desiredTradeType = desiredPrice > Symbol.Bid ? TradeType.Sell : TradeType.Buy;
        PlaceLimitOrder(desiredTradeType, SymbolName, 10000, desiredPrice);
    }
}
1
2
3
4
5
6
7
8
class Sample_cBot():
    def on_start(self):
        api.Chart.MouseUp += self.on_chart_mouse_up        

    def on_chart_mouse_up(self, args):
        desiredPrice = api.Chart.YToYValue(args.MouseY)
        desiredTradeType = TradeType.Sell if desiredPrice > api.Symbol.Bid else TradeType.Buy
        api.PlaceLimitOrder(desiredTradeType, api.SymbolName, 10000, desiredPrice)

Wykonywanie asynchroniczne

Powyższe przykłady kodu zostały zaprojektowane w celu implementacji robotów handlowych przy użyciu wykonywania synchronicznego. Zarówno C#, jak i Python obsługują operacje asynchroniczne, umożliwiając cBotowi wykonywanie kilku działań w tym samym przedziale czasowym.

Asynchroniczna realizacja zleceń rynkowych

Składnia metod asynchronicznych jest podobna do składni metod synchronicznych. Chociaż przyjmują te same typy argumentów, ich typem zwracanym jest TradeOperation zamiast TradeResult.

  • Podstawowe operacje asynchroniczne

    Poniższy cBot demonstruje, jak działają operacje asynchroniczne. Tworzone jest zlecenie rynkowe; w następnym warunku cBot sprawdza, czy operacja jest wykonywana.

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    [Robot()]
    public class Sample_cBot : Robot
    {
        protected override void OnStart()
        {
            var operation = ExecuteMarketOrderAsync(TradeType.Buy, SymbolName, 10000);
    
            if (operation.IsExecuting)
            {
                Print("Operation Is Executing");
            }
        }
    }
    
    1
    2
    3
    4
    5
    6
    class Sample_cBot():
        def on_start(self):
            operation = api.ExecuteMarketOrderAsync(TradeType.Buy, api.SymbolName, 10000)
    
            if operation.IsExecuting:
                api.Print("Operation Is Executing")
    

    Wynik dziennika

    • cBot "New cBot" został pomyślnie uruchomiony dla EURUSD, h1.
    • Realizacja zlecenia rynkowego kupna 10000 EURUSD
    • Operacja jest wykonywana
    • Realizacja zlecenia rynkowego kupna 10000 EURUSD POWIODŁA SIĘ, Position PID14579532
  • Realizacja zlecenia

    Następny przykład podkreśla różnicę między metodami synchronicznymi i asynchronicznymi.

    cBot sprawdza, czy operacja jest wykonywana zaraz po wywołaniu metody asynchronicznej. Robi to ponownie po wywołaniu metody synchronicznej. Dane wyjściowe dziennika dla tych dwóch działań są różne.

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    [Robot()]
    public class Sample_cBot : Robot
    {
        protected override void OnStart()
        {
            var operation = ExecuteMarketOrderAsync(TradeType.Buy, SymbolName, 10000);
            Print(operation.IsExecuting ? "Operation Is Executing" : "Operation executed");
            ExecuteMarketOrder(TradeType.Buy, SymbolName, 20000);
            Print(operation.IsExecuting ? "Operation Is Executing" : "Operation executed");
        }
    }
    
    1
    2
    3
    4
    5
    6
    class Sample_cBot():
        def on_start(self):
            operation = api.ExecuteMarketOrderAsync(TradeType.Buy, api.SymbolName, 10000)
            api.Print("Operation Is Executing" if operation.IsExecuting else "Operation executed")
            api.ExecuteMarketOrder(TradeType.Buy, api.SymbolName, 20000)
            api.Print("Operation Is Executing" if operation.IsExecuting else "Operation executed")
    

    Wynik dziennika

    • cBot "New cBot" został pomyślnie uruchomiony dla EURUSD, h1.
    • Realizacja zlecenia rynkowego kupna 10000 EURUSD
    • Operacja jest wykonywana
    • Realizacja zlecenia rynkowego kupna 20000 EURUSD
    • Realizacja zlecenia rynkowego kupna 10000 EURUSD POWIODŁA SIĘ, Position PID14579541
    • Realizacja zlecenia rynkowego kupna 20000 EURUSD POWIODŁA SIĘ, Position PID14579542
    • Operacja zrealizowana
  • Realizacja zlecenia z większą liczbą parametrów

    Poniższy cBot składa zlecenie określając jego etykietę ("myLabel"), poziomy ochrony (10, 10), symbol (SymbolName) i wolumen (10000).

    Przykład zawiera również kolekcję Positions i metodę FindAll(). Find() i FindAll() mogą być używane do znajdowania pozycji z tą samą etykietą, symbolem i typem transakcji.

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    [Robot()]
    public class Sample_cBot : Robot
    {
        protected override void OnStart()
        {
            ExecuteMarketOrderAsync(TradeType.Buy, SymbolName, 10000, "myLabel", 10, 10);
        }
        protected override void OnTick()
        {
            var positions = Positions.FindAll("myLabel", SymbolName, TradeType.Buy);
    
            if (positions.Length == 0)
                return;
    
            foreach (var position in positions)
                Print("Buy at {0} SL {1}", position.EntryPrice, position.StopLoss);
    
            Stop();
        }
    }
    
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    class Sample_cBot():
        def on_start(self):
            api.ExecuteMarketOrderAsync(TradeType.Buy, api.SymbolName, 10000, "myLabel", 10, 10)
    
        def on_tick(self):
            positions = api.Positions.FindAll("myLabel", api.SymbolName, TradeType.Buy)
    
            if positions.Length == 0:
                return
    
            for position in positions:
                api.Print(f"Buy at {position.EntryPrice} SL {position.StopLoss}")
    
            api.Stop()            
    

    Wynik dziennika

    • cBot "New cBot" został pomyślnie uruchomiony dla EURUSD, h1.
    • Realizacja zlecenia rynkowego kupna 10000 EURUSD (SL: 10, TP: 10)
    • Realizacja zlecenia rynkowego kupna 10000 EURUSD (SL: 10, TP: 10) POWIODŁA SIĘ, Position PID14579719
    • Kupno po 1.19087 SL null
    • Kupno po 1.19357 SL 1.19257
    • cBot "New cBot" został zatrzymany dla EURUSD, h1.

Asynchroniczna modyfikacja pozycji

Poniższy cBot składa zlecenie rynkowe, a następnie modyfikuje nowo otwartą pozycję.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
[Robot()]
public class Sample_cBot : Robot
{
    protected override void OnStart()
    {
        ExecuteMarketOrderAsync(TradeType.Buy, SymbolName, 10000, "myLabel", null, 10);
    }

    protected override void OnTick()
    {
        Position myPosition = Positions.Find("myLabel");
        if (myPosition != null && myPosition.StopLoss == null)
        {
            double stopLoss = Symbol.Bid - 10 * Symbol.PipSize;
            ModifyPositionAsync(myPosition, stopLoss, myPosition.TakeProfit);
        }
    }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
class Sample_cBot():
    def on_start(self):
        api.ExecuteMarketOrderAsync(TradeType.Buy, api.SymbolName, 10000, "myLabel", None, 10)

    def on_tick(self):
        myPosition = Positions.Find("myLabel")

        if myPosition is None or myPosition.StopLoss is not None:
            return

        stopLoss = api.Symbol.Bid - 10 * api.Symbol.PipSize

        api.ModifyPositionAsync(myPosition, stopLoss, myPosition.TakeProfit)        

Wynik dziennika

  • cBot "New cBot" został pomyślnie uruchomiony dla EURUSD, h1.
  • Realizacja zlecenia rynkowego kupna 10000 EURUSD (TP: 10)
  • Realizacja zlecenia rynkowego kupna 10000 EURUSD (TP: 10) POWIODŁA SIĘ, Position PID14579736
  • Modyfikacja pozycji PID14579300 (SL: 1.19213, TP: null)
  • Modyfikacja pozycji PID14579300 (SL: 1.19213, TP: null) POWIODŁA SIĘ, Position PID14579300

Asynchroniczne zamykanie pozycji

Następny przykład demonstruje asynchroniczne zamykanie pozycji, jeśli istnieje.

Metoda Find() jest używana do przeszukiwania kolekcji Positions w poszukiwaniu pozycji z określoną etykietą.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
[Robot()]
public class Sample_cBot : Robot
{
    protected override void OnStart()
    {
        ExecuteMarketOrderAsync(TradeType.Buy, Symbol, 10000, "myLabel", null, 10);
    }

    protected override void OnTick()
    {
        Position myPosition = Positions.Find("myLabel");
        if (myPosition != null && myPosition.GrossProfit > 10)
        {
            ClosePositionAsync(myPosition);
            Stop();
        }
    }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
class Sample_cBot():
    def on_start(self):
        api.ExecuteMarketOrderAsync(TradeType.Buy, api.SymbolName, 10000, "myLabel", None, 10)

    def on_tick(self):
        myPosition = Positions.Find("myLabel")

        if myPosition is None or myPosition.GrossProfit <= 10:
            return

        api.ClosePositionAsync(myPosition)
        api.Stop()        

Wynik dziennika

  • cBot "New cBot" został pomyślnie uruchomiony dla EURUSD, h1.
  • Realizacja zlecenia rynkowego kupna 10000 EURUSD (TP: 10)
  • Realizacja zlecenia rynkowego kupna 10000 EURUSD (TP: 10) POWIODŁA SIĘ, Position PID14579740
  • Zamykanie pozycji PID14579300
  • Zamykanie pozycji PID14579300 POWIODŁO SIĘ, Position PID14579300
  • cBot "New cBot" został zatrzymany dla EURUSD, h1.

Asynchroniczne składanie zleceń z limitem i zleceń stop

Jak wspomniano powyżej, składanie zleceń oczekujących jest podobne do tworzenia zleceń rynkowych.

Istnieją jednak pewne niewielkie różnice w argumentach między tymi dwiema metodami. Dopuszczalny poślizg nie występuje na liście argumentów. Ponadto musisz określić cenę docelową i możesz przekazać opcjonalny argument określający datę wygaśnięcia zlecenia.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
[Robot()]
public class Sample_cBot : Robot
{
    protected override void OnStart()
    {
        var expiry = Server.Time.AddHours(12);
        PlaceLimitOrderAsync(TradeType.Buy, SymbolName, 10000, Symbol.Bid, "myLabel", null, null, expiry);
        PlaceStopOrderAsync(TradeType.Buy, SymbolName, 10000, Symbol.Ask + 10 * Symbol.PipSize, "myLabel", null, null, expiry);
    }
}
1
2
3
4
5
class Sample_cBot():
    def on_start(self):
        expiry = api.Server.Time.AddHours(12)
        api.PlaceLimitOrderAsync(TradeType.Buy, api.SymbolName, 10000, api.Symbol.Bid, "myLabel", None, None, expiry)
        api.PlaceStopOrderAsync(TradeType.Buy, api.SymbolName, 10000, api.Symbol.Ask + 10 * api.Symbol.PipSize, "myLabel", None, None, expiry)    

Wynik dziennika

  • cBot "New cBot" został pomyślnie uruchomiony dla EURUSD, h1.
  • Składanie zlecenia z limitem kupna 10000 EURUSD (Cena: 1.19382, ExpireTime: 12/05/2018 00:18:19)
  • Składanie zlecenia Stop kupna 10000 EURUSD (Cena: 1.19487, ExpireTime: 12/05/2018 00:18:19)
  • Składanie zlecenia z limitem kupna 10000 EURUSD (Cena: 1.19382, ExpireTime: 12/05/2018 00:18:19) POWIODŁO SIĘ, PendingOrder OID25221859
  • Składanie zlecenia Stop kupna 10000 EURUSD (Cena: 1.19487, ExpireTime: 12/05/2018 00:18:19) POWIODŁO SIĘ, PendingOrder OID25221860

Modyfikuj zlecenia oczekujące asynchronicznie

Poniższy cBot modyfikuje zlecenia z limitem asynchronicznie.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
[Robot()]
public class Sample_cBot : Robot
{
    protected override void OnStart()
    {
        var expiry = Server.Time.AddHours(12);
        PlaceLimitOrderAsync(TradeType.Buy, SymbolName, 10000, Symbol.Bid, "myLabel", null, 10, expiry);

    }
    protected override void OnTick()
    {
        foreach (var order in PendingOrders)
        {
            if (order.Label == "myLabel" && order.StopLoss == null)
                ModifyPendingOrderAsync(order, order.TargetPrice, 10, 10, null);
        }
    }
}
1
2
3
4
5
6
7
8
9
class Sample_cBot():
    def on_start(self):
        expiry = api.Server.Time.AddHours(12)
        api.PlaceLimitOrderAsync(TradeType.Buy, api.SymbolName, 10000, api.Symbol.Bid, "myLabel", None, 10, expiry)

    def on_tick(self):
        for order in api.PendingOrders:
            if order.Label == "myLabel" and order.StopLoss is None:
                api.ModifyPendingOrderAsync(order, order.TargetPrice, 10, 10, None)

Wynik dziennika

  • cBot "New cBot" został pomyślnie uruchomiony dla EURUSD, h1.
  • Składanie zlecenia z limitem kupna 10000 EURUSD (Cena: 1.19347, TP: 10, ExpireTime: 12/05/2018 00:22:08)
  • Modyfikacja zlecenia oczekującego OID25221860 (Wolumen: 10000, Cena: 1.19487, SL: 10, TP: 10, ExpireTime: 12/05/2018 00:18:19)
  • Składanie zlecenia z limitem kupna 10000 EURUSD (Cena: 1.19347, TP: 10, ExpireTime: 12/05/2018 00:22:08) POWIODŁO SIĘ, PendingOrder OID25221906
  • Modyfikacja zlecenia oczekującego OID25221860 (Wolumen: 10000, Cena: 1.19487, SL: 10, TP: 10, ExpireTime: 12/05/2018 00:18:19) POWIODŁO SIĘ, PendingOrder OID25221860
  • Modyfikacja zlecenia oczekującego OID25221906 (Wolumen: 10000, Cena: 1.19347, SL: 10, TP: 10, ExpireTime: 12/05/2018 00:22:08)
  • Modyfikacja zlecenia oczekującego OID25221906 (Wolumen: 10000, Cena: 1.19347, SL: 10, TP: 10, ExpireTime: 12/05/2018 00:22:08) POWIODŁO SIĘ, PendingOrder OID25221906

Anuluj zlecenia oczekujące asynchronicznie

  • Anuluj wszystkie zlecenia oczekujące

    Poniższy cBot asynchronicznie anuluje wszystkie aktualnie oczekujące zlecenia.

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    [Robot()]
    public class Sample_cBot : Robot
    {
        protected override void OnBar()
        {
            foreach (var pendingOrder in PendingOrders)
            {
                CancelPendingOrderAsync(pendingOrder);
            }
        }
    }
    
    1
    2
    3
    4
    class Sample_cBot():
        def on_bar(self):
            for order in api.PendingOrders:
                api.CancelPendingOrderAsync(order)
    

    Wynik dziennika

    • cBot "cancel pending order" został pomyślnie uruchomiony dla EURUSD, h1.
    • Anulowanie zlecenia oczekującego OID274705
    • Anulowanie zlecenia oczekującego OID274706
    • Anulowanie zlecenia oczekującego OID274707
    • Anulowanie zlecenia oczekującego OID274708
    • Anulowanie zlecenia oczekującego OID274709
    • Anulowanie zlecenia oczekującego OID274705 POWIODŁO SIĘ, PendingOrder OID274705
    • Anulowanie zlecenia oczekującego OID274706 POWIODŁO SIĘ, PendingOrder OID274706
    • Anulowanie zlecenia oczekującego OID274707 POWIODŁO SIĘ, PendingOrder OID274707
    • Anulowanie zlecenia oczekującego OID274708 POWIODŁO SIĘ, PendingOrder OID274708
    • Anulowanie zlecenia oczekującego OID274709 POWIODŁO SIĘ, PendingOrder OID274709
  • Anuluj zlecenia oczekujące z określoną etykietą

    Ten cBot anuluje tylko zlecenia oczekujące z określoną etykietą.

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    [Robot()]
    public class Sample_cBot : Robot
    {
        protected override void OnBar()
        {
            foreach (var pendingOrder in PendingOrders)
            {
                if (pendingOrder.Label == "myLabel")
                    CancelPendingOrderAsync(pendingOrder);
            }
        }
    }
    
    1
    2
    3
    4
    5
    class Sample_cBot():
        def on_bar(self):
            for order in api.PendingOrders:
                if order.Label == "myLabel":
                    api.CancelPendingOrderAsync(order)
    

Funkcje wywołania zwrotnego dla metod asynchronicznych

Po zwróceniu wyniku, korzystanie z operacji asynchronicznych często wymaga kontrolowania wykonania. Aby sobie z tym poradzić, możesz dodać funkcję wywołania zwrotnego na końcu listy parametrów wszystkich metod asynchronicznych.

Ta funkcja zostanie wywołana, gdy tylko zostanie otrzymana odpowiedź z serwera. Na przykład może zostać wywołana, gdy pozycja zostanie otwarta, zmodyfikowana lub zamknięta.

  • Asynchroniczne zlecenie rynkowe z wywołaniem zwrotnym

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    [Robot()]
    public class Sample_cBot : Robot
    {
        protected override void OnStart()
        {
            var operation = ExecuteMarketOrderAsync(TradeType.Buy, SymbolName, 10000, PositionOpened);
            if (operation.IsExecuting)
                Print(operation.ToString());
            else
                Print(operation.TradeResult.ToString());
    
        }
    
        private void PositionOpened(TradeResult tradeResult)
        {
            var position = tradeResult.Position;
            Print(tradeResult.ToString());
            if (tradeResult.IsSuccessful)
                Print("Position {0} opened at {1}", position.Id, position.EntryPrice);
        }
    }
    
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    from System import Action
    
    class Sample_cBot():
        def on_start(self):
            operation = api.ExecuteMarketOrderAsync(TradeType.Buy, api.SymbolName, 10000, Action[TradeResult](self.on_position_opened))
    
            if (operation.IsExecuting)
                api.Print(operation.ToString())
            else
                api.Print(operation.TradeResult.ToString())
    
        def on_position_opened(self, tradeResult):
            position = tradeResult.Position
    
            api.Print(tradeResult.ToString())
    
            if tradeResult.IsSuccessful:
                api.Print(f"Position {position.Id} opened at {position.EntryPrice}")
    

    Wynik dziennika

    • cBot "New cBot" został pomyślnie uruchomiony dla EURUSD, h1.
    • Wykonywanie zlecenia rynkowego kupna 10000 EURUSD
    • TradeOperation (Wykonywanie zlecenia rynkowego kupna 10000 EURUSD WYKONYWANIE)
    • Wykonywanie zlecenia rynkowego kupna 10000 EURUSD POWIODŁO SIĘ, Position PID14579835
    • TradeResult (Success, Position: PID14579835)
    • Pozycja 14579835 otwarta po 1.19414
  • Używanie wyrażeń lambda

    Zamiast definiować nazwaną metodę wywołania zwrotnego, możesz użyć wyrażeń lambda.

    W poniższym przykładzie, gdy zlecenie zostanie złożone, opis wyniku zostanie wydrukowany w dzienniku.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    [Robot()]
    public class Sample_cBot : Robot
    {
        protected override void OnStart()
        {
            PlaceLimitOrderAsync(TradeType.Buy, SymbolName, 10000,
                    Symbol.Ask - 20 * Symbol.PipSize, "myLabel", result => Print(result.ToString()));
        }
    }
    
    1
    2
    3
    4
    5
    from System import Action
    
    class Samples():
        def on_start(self):
            operation = api.PlaceLimitOrderAsync(TradeType.Buy, api.SymbolName, 10000, api.Symbol.Ask - 20 * api.Symbol.PipSize, "myLabel", Action[TradeResult](lambda result: api.Print(result.ToString())))
    

    Log output

    • cBot "New cBot" został pomyślnie uruchomiony dla EURUSD, h1.
    • Składanie zlecenia z limitem kupna 10000 EURUSD (Cena: 1.19320)
    • Składanie zlecenia z limitem kupna 10000 EURUSD (Cena: 1.19320) POWIODŁO SIĘ, PendingOrder OID25222083
    • TradeResult (Success, PendingOrder: OID25222083)

Image title