콘텐츠로 이동

Python으로 트레이딩 봇을 만드는 방법

이 글과 비디오는 Python으로 트레이딩 로봇을 만드는 단계별 지침을 제공합니다.

참고

cTrader는 네이티브 Python 지원을 제공하는 유일한 주요 트레이딩 플랫폼으로, Python 코드를 작성하고 cTrader Windows 또는 Mac에서 직접 봇, 기술 지표 및 도구를 구축할 수 있습니다. 어댑터나 복잡한 우회 방법이 필요하지 않습니다.

트레이딩 로봇 만들기

Algo 앱의 cBots 탭에서 새로 만들기 버튼을 클릭하여 새로운 트레이딩 봇 만들기를 시작합니다.

cBot에 이름을 지정하고 프로그래밍 언어로 Python을 선택합니다.

참고

cTrader는 다양한 전략과 자동화된 트레이딩 작업을 다루는 Python으로 작성된 여러 미리 만들어진 알고리즘을 제공합니다. 이러한 알고리즘 템플릿은 이미 트레이딩 로직과 사용자 정의 가능한 매개변수를 포함하고 있으며, 저장하고 빌드하면 바로 실행할 준비가 되어 있습니다.

생성 방법으로 템플릿 사용을 선택하고, Grid Sample을 선택한 후 만들기를 클릭합니다.

Grid cBot은 심볼에 대한 여러 매수 또는 매도 주문을 정기적인 가격 간격 또는 단계에 배치하여 포지션의 그리드를 형성하는 그리드 트레이딩 전략을 구현합니다.

코드를 검증하기 위해 cBot을 빌드해 보겠습니다.

Ctrl+B를 누르거나 빌드를 클릭합니다.

Cmd+B를 누르거나 빌드 아이콘을 클릭합니다.

지표 추가

트레이딩 봇의 정확도를 높이기 위해 지표를 통합해 보겠습니다.

Relative Strength Index (RSI)는 시장에서 과매수 또는 과매도 상태를 신호하는 인기 있는 지표입니다. 이 지표는 시장이 한 방향으로 과도하게 움직일 때 새로운 포지션을 열지 않도록 cBot을 도울 수 있습니다.

로봇 로직에 RSI를 통합합니다. 기본 기간을 14로 설정하고 과매수 및 과매도 수준을 각각 70과 30으로 설정하여 지표를 초기화합니다. 심볼의 종가를 사용하여 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)

포지션을 열기 전에 RSI 조건이 거래를 허용하는지 확인하는 로직을 추가합니다. 필터가 거래를 차단하면 현재 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()))

가격이 충분히 움직였고 RSI 값이 중립 범위 내에 있을 때만 그리드 포지션이 열리도록 하는 코드를 작성합니다. 안정성을 위해 마지막으로 닫힌 바의 RSI 값을 사용하고 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)

현재 시장 가격과 포지션의 진입 가격 간의 핍 단위 거리에 대한 계산 로직을 조정합니다.

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

통합된 RSI 지표가 포함된 전체 Python 코드를 아래에서 복사할 수 있습니다:

 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

인스턴스 시작

cBot으로 돌아가서 빌드해 보겠습니다. 이제 모든 인스턴스에 대해 cBot 시작 아이콘을 클릭하면 트레이딩 봇이 실행되기 시작합니다.

또는 인스턴스 추가를 클릭하고 선호하는 인스턴스 매개변수를 지정한 후 새 인스턴스를 추가하고 시작할 수 있습니다.

새 인스턴스를 추가하고 사용자 정의함으로써 다른 심볼, 기간 또는 매개변수에서 동시에 cBot을 실행할 수 있습니다.

다른 곳에서 봇 실행

클라우드 동기화가 활성화되면 cBot은 cTID가 활성화된 모든 cTrader 애플리케이션에 자동으로 나타납니다. cTrader Mobile 및 Web을 포함한 모든 cTrader 앱에서 동일한 트레이딩 로봇을 클라우드에서 시작할 수 있습니다.

cTrader Algo에서 cBot을 시작합니다.

이 글은 Python 트레이딩 로봇을 만들고 시작하는 방법을 보여주어 전략을 자동화하고 모든 장치에서 알고리즘을 실행할 수 있도록 도와줍니다.

Image title