Przejdź do treści

Jak stworzyć robota handlowego w Pythonie

Ten artykuł i film oferują instrukcje krok po kroku dotyczące tworzenia robota handlowego w Pythonie.

Uwaga

cTrader to jedyna główna platforma handlowa z natywnym wsparciem Pythona, umożliwiająca pisanie kodu w Pythonie i tworzenie botów, wskaźników technicznych i narzędzi bezpośrednio w cTrader Windows lub Mac. Nie jest wymagany żaden adapter ani skomplikowane obejście.

Stwórz robota handlowego

W zakładce cBots aplikacji Algo kliknij przycisk New, aby rozpocząć tworzenie nowego robota handlowego.

Nadaj cBotowi nazwę i wybierz Python jako język programowania.

Uwaga

cTrader udostępnia kilka gotowych algorytmów w Pythonie obejmujących szeroki zakres strategii i zautomatyzowanych działań handlowych. Te szablony algorytmów zawierają już logikę handlową i konfigurowalne parametry i są gotowe do uruchomienia po zapisaniu i zbudowaniu.

Wybierz Using template jako metodę tworzenia, wybierz Grid Sample, a następnie kliknij Create.

Grid cBot implementuje strategię handlu siatką, w której wiele zleceń kupna lub sprzedaży dla symbolu jest umieszczanych w regularnych odstępach cenowych lub krokach, tworząc siatkę pozycji.

Teraz zbudujmy naszego cBota, aby zwalidować jego kod.

Naciśnij Ctrl+B lub kliknij Build.

Naciśnij Cmd+B lub kliknij ikonę Build.

Dodaj wskaźnik

Włączmy wskaźnik do naszego robota handlowego, aby poprawić jego dokładność.

Relative Strength Index (RSI) to popularny wskaźnik, który sygnalizuje wykupienie lub wyprzedanie na rynku. Ten wskaźnik może pomóc naszemu cBotowi uniknąć otwierania nowych pozycji, gdy rynek jest nadmiernie rozciągnięty w jednym kierunku.

Zintegruj RSI z logiką robota. Zainicjuj wskaźnik z domyślnym okresem 14 i ustaw poziomy wykupienia i wyprzedania odpowiednio na 70 i 30. Użyj cen zamknięcia symbolu, aby utworzyć RSI.

1
2
3
4
self.rsi_period = getattr(api, "RsiPeriod", 14)
self.rsi_overbought = getattr(api, "RsiOverbought", 70)
self.rsi_oversold = getattr(api, "RsiOversold", 30)
self.rsi = api.Indicators.RelativeStrengthIndex(api.Bars.ClosePrices, self.rsi_period)

Dodaj logikę sprawdzającą, czy warunki RSI pozwalają na transakcję przed otwarciem pozycji. Jeśli filtr blokuje transakcję, zaloguj komunikat pokazujący bieżącą wartość RSI.

1
2
3
4
5
6
if len(self.get_grid_positions()) == 0:
    # self.open_position()
    if self.passes_rsi_filter():
        self.open_position()
    else:
        api.Print("RSI filter blocked initial entry (RSI={:.2f})".format(self.get_rsi_value()))

Napisz kod, który zapewnia, że pozycja siatki jest otwierana tylko wtedy, gdy cena przesunęła się wystarczająco i wartość RSI mieści się w neutralnym zakresie. Użyj wartości RSI ostatniego zamkniętego słupka dla stabilności i wydrukuj komunikat, gdy zostanie zablokowany przez filtr RSI.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
if distance >= api.StepPips:
    # self.open_position()
    if self.passes_rsi_filter():
        self.open_position()
    else:
        api.Print("RSI filter: no new entry (RSI={:.2f}, range {}-{})"
                    .format(self.get_rsi_value(), self.rsi_oversold, self.rsi_overbought))

def get_rsi_value(self):
    # Use the last CLOSED bar for stability
    return self.rsi.Result.Last(1)

def passes_rsi_filter(self):
    r = self.get_rsi_value()
    return (r > self.rsi_oversold) and (r < self.rsi_overbought)

Dostosuj logikę obliczania odległości w pipsach między bieżącą ceną rynkową a ceną otwarcia pozycji.

1
2
3
4
5
6
7
def get_distance_in_pips(self, position):
    # return (position.EntryPrice - api.Symbol.Ask if position.TradeType == TradeType.Buy else api.Symbol.Bid - position.EntryPrice) / api.Symbol.PipSize
    if position.TradeType == TradeType.Buy:
        diff = position.EntryPrice - api.Symbol.Ask
    else:
        diff = api.Symbol.Bid - position.EntryPrice
    return diff / api.Symbol.PipSize

Możesz skopiować pełny kod Pythona ze zintegrowanym wskaźnikiem RSI poniżej:

 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
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
import clr

clr.AddReference("cAlgo.API")

# Import cAlgo API types
from cAlgo.API import *

# Import trading wrapper functions
from robot_wrapper import *

class SupercBot():
    def on_start(self):
        self.volumeInUnits = api.Symbol.QuantityToVolumeInUnits(api.VolumeInLots)
        self.enoughMoney = True

        self.rsi_period = getattr(api, "RsiPeriod", 14)
        self.rsi_overbought = getattr(api, "RsiOverbought", 70)
        self.rsi_oversold = getattr(api, "RsiOversold", 30)
        self.rsi = api.Indicators.RelativeStrengthIndex(api.Bars.ClosePrices, self.rsi_period)

        if len(self.get_grid_positions()) == 0:
            if self.passes_rsi_filter():
                self.open_position()
            else:
                api.Print("RSI filter blocked initial entry (RSI={:.2f})".format(self.get_rsi_value()))

    def on_tick(self):
        grid_positions = self.get_grid_positions()
        net_profit_sum = sum([p.NetProfit for p in grid_positions])
        if net_profit_sum >= api.TargetProfit:
            api.Print("Target profit is reached. Closing all grid positions")
            self.close_grid_positions()
            api.Print("All grid positions are closed. Stopping cBot")
            api.Stop()

        if len(grid_positions) > 0 and self.enoughMoney == True:
            position_with_highest_pips = sorted(grid_positions, key=lambda pos: pos.Pips, reverse=True)[0]
            distance = self.get_distance_in_pips(position_with_highest_pips)          
            if distance >= api.StepPips:
                if self.passes_rsi_filter():
                    self.open_position()
                else:
                    api.Print("RSI filter: no new entry (RSI={:.2f}, range {}-{})"
                              .format(self.get_rsi_value(), self.rsi_oversold, self.rsi_overbought))

    def get_rsi_value(self):
        # Use the last CLOSED bar for stability
        return self.rsi.Result.Last(1)

    def passes_rsi_filter(self):
        r = self.get_rsi_value()
        return (r > self.rsi_oversold) and (r < self.rsi_overbought)

    def get_grid_positions(self):
        return [pos for pos in api.Positions if pos.SymbolName == api.SymbolName and pos.TradeType == api.TradeType]

    def open_position(self):
        result = api.ExecuteMarketOrder(api.TradeType, api.SymbolName, self.volumeInUnits, "Grid")
        if result.Error == ErrorCode.NoMoney:
            self.enoughMoney = False
            api.Print("Not enough money to open additional positions")

    def close_grid_positions(self):
        for position in self.get_grid_positions():
            position.Close()

        if len(self.get_grid_positions()) > 0:
            self.close_grid_positions()

    def get_distance_in_pips(self, position):
        if position.TradeType == TradeType.Buy:
            diff = position.EntryPrice - api.Symbol.Ask
        else:
            diff = api.Symbol.Bid - position.EntryPrice
        return diff / api.Symbol.PipSize

Uruchom wystąpienie

Wróćmy do naszego cBota i zbudujmy go. Teraz kliknij ikonę Start cBot dla dowolnego wystąpienia, a robot handlowy rozpocznie działanie.

Alternatywnie możesz kliknąć Add instance, określić preferowane parametry wystąpienia, dodać nowe wystąpienie i je uruchomić.

Poprzez dodawanie i dostosowywanie nowych wystąpień możesz uruchamiać cBota jednocześnie na różnych symbolach, okresach lub parametrach.

Uruchom bota w innym miejscu

Przy włączonej synchronizacji z chmurą cBot pojawia się automatycznie we wszystkich aplikacjach cTrader, w których Twój cTID jest aktywny. Możemy uruchomić tego samego robota handlowego w chmurze w dowolnej aplikacji cTrader, w tym cTrader Mobile i Web.

W cTrader Algo uruchom cBota.

Ten artykuł pokazał, jak stworzyć robota handlowego w Pythonie i go uruchomić, umożliwiając automatyzację strategii i uruchamianie algorytmów na dowolnym urządzeniu.

Image title