콘텐츠로 이동

수동 거래 전략 자동화 방법

자동화 또는 알고리즘 트레이딩은 수동 거래에 비해 여러 가지 장점을 제공합니다:

  • 자동화 시스템은 감정적인 의사 결정을 제거하고 더 정확하고 빠르며 효율적으로 거래를 실행합니다.
  • 알고리즘은 고급 거래 전략을 일관되게 구현하고 위험 관리 조치를 신뢰할 수 있게 시행합니다.
  • 알고리즘은 역사적 데이터를 사용하여 전략을 백테스트하고 여러 자산과 시장에 동시에 분산 투자할 수 있게 합니다.

cTrader Algo API는 트레이더가 복잡한 수동 전략을 자동화할 수 있도록 하여 알고리즘 트레이딩의 많은 장점을 활용할 수 있게 합니다. 이 글과 해당 비디오에서는 복잡한 수동 전략을 자동화하고 일련의 작업을 알고리즘으로 변환하는 방법을 배우게 됩니다.

수동 전략 패턴 식별

알고리즘을 개발하기 위해, 우리가 수동으로 hammer 패턴을 롱 진입에, hanging man 패턴을 숏 진입에 사용한다고 가정해 보겠습니다.

hammer는 하락 추세 중에 발생하며 잠재적인 강세 반전을 시사합니다. hammer 패턴은 매수 진입을 식별하는 데 사용됩니다.

hanging man은 상승 추세 중에 나타나며 잠재적인 약세 반전을 나타냅니다. hanging man 패턴은 매도 진입을 식별하는 데 사용됩니다.

수동 전략을 거래하는 cBot 개발

cTrader Algo에서 이전 섹션에서 설명한 전략을 구현하는 알고리즘을 만들어 보겠습니다.

cBot 탭 아래의 새로운 버튼을 클릭하세요. 이름 필드에 패턴 전략를 입력하고 생성를 클릭하세요.

OnBarClosed() 메서드에서 우리 전략의 로직을 구현합니다. 우리의 진입은 다음 두 가지 조건을 충족해야 합니다:

  • 종가가 고가와 일치해야 합니다.
  • 캔들 크기가 캔들 바디보다 최소 5배 이상 커야 합니다.

먼저 Volume, StopLoss, TakeProfit 매개 변수를 정의합니다.

1
2
3
4
5
6
7
8
[Parameter(DefaultValue = 1000)]
public double Volume { get; set; }

[Parameter(DefaultValue = 10)]
public double StopLoss { get; set; }

[Parameter(DefaultValue = 10)]
public double TakeProfit { get; set; }

그런 다음 필요한 조건이 충족될 때 매수 거래를 실행하는 코드 스니펫을 작성합니다.

1
2
3
4
5
if (Bars.Last(0).Close == Bars.Last(0).High &&
            (Bars.Last(0).Close - Bars.Last(0).Open) < (Bars.Last(0).Close - Bars.Last(0).Low) * 0.2)
{
    ExecuteMarketOrder(TradeType.Buy, SymbolName, Volume, InstanceId, StopLoss, TakeProfit);
}
1
2
3
bar = api.Bars.Last(0)
if bar.Close == bar.High and (bar.Close - bar.Open) < (bar.Close - bar.Low) * 0.2:
    api.ExecuteMarketOrder(TradeType.Buy, api.SymbolName, api.Volume, api.InstanceId, api.StopLoss, api.TakeProfit)

반대편에서는 매수 진입과 마찬가지로 매도 진입을 위한 조건이 충족되어야 합니다:

  • 종가가 저가와 일치해야 합니다.
  • 캔들 크기가 캔들 바디보다 최소 5배 이상 커야 합니다.

마찬가지로 필요한 조건이 충족될 때 매도 거래를 실행하는 코드 스니펫을 작성합니다.

1
2
3
4
5
if (Bars.Last(0).Close == Bars.Last(0).Low &&
                (Bars.Last(0).Open - Bars.Last(0).Close) < (Bars.Last(0).High - Bars.Last(0).Close) * 0.2)
{
    ExecuteMarketOrder(TradeType.Sell, SymbolName, Volume, InstanceId, StopLoss, TakeProfit);
}
1
2
if bar.Close == bar.Low and (bar.Open - bar.Close) < (bar.High - bar.Close) * 0.2:
    api.ExecuteMarketOrder(TradeType.Sell, api.SymbolName, api.Volume, api.InstanceId, api.StopLoss, api.TakeProfit)

아래에서 전체 코드를 복사할 수 있습니다:

 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
using System;
using cAlgo.API;
using cAlgo.API.Collections;
using cAlgo.API.Indicators;
using cAlgo.API.Internals;

namespace cAlgo.Robots
{
    [Robot(AccessRights = AccessRights.None, AddIndicators = true)]
    public class PatternsStrategy : Robot
    {
        [Parameter(DefaultValue = 1000)]
        public double Volume { get; set; }

        [Parameter(DefaultValue = 10)]
        public double StopLoss { get; set; }

        [Parameter(DefaultValue = 10)]
        public double TakeProfit { get; set; }

        protected override void OnStart()
        {

        }

        protected override void OnBarClosed()
        {
            if (Bars.Last(0).Close == Bars.Last(0).High &&
            (Bars.Last(0).Close - Bars.Last(0).Open) < (Bars.Last(0).Close - Bars.Last(0).Low) * 0.2)
            {
                ExecuteMarketOrder(TradeType.Buy, SymbolName, Volume, InstanceId, StopLoss, TakeProfit);
            }

            if (Bars.Last(0).Close == Bars.Last(0).Low &&
            (Bars.Last(0).Open - Bars.Last(0).Close) < (Bars.Last(0).High - Bars.Last(0).Close) * 0.2)
            {
                ExecuteMarketOrder(TradeType.Sell, SymbolName, Volume, InstanceId, StopLoss, TakeProfit);
            }

        }

        protected override void OnStop()
        {

        }
    }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
import clr
clr.AddReference("cAlgo.API")
from cAlgo.API import *
from robot_wrapper import *

class PatternsStrategy():
    def on_start(self):
        pass

    def on_bar_closed(self):
        bar = api.Bars.Last(0)

        if bar.Close == bar.High and (bar.Close - bar.Open) < (bar.Close - bar.Low) * 0.2:
            api.ExecuteMarketOrder(TradeType.Buy, api.SymbolName, api.Volume, api.InstanceId, api.StopLoss, api.TakeProfit)

        if bar.Close == bar.Low and (bar.Open - bar.Close) < (bar.High - bar.Close) * 0.2:
            api.ExecuteMarketOrder(TradeType.Sell, api.SymbolName, api.Volume, api.InstanceId, api.StopLoss, api.TakeProfit)

    def on_stop(self):
        pass

cBot을 빌드하려면 Ctrl+B를 누르거나 빌드를 클릭하세요.

cBot을 백테스트하려면 먼저 인스턴스를 추가합니다. 로컬에서 옵션을 선택하고 선호하는 매개 변수를 지정한 후 인스턴스 추가 버튼을 클릭하세요.

그런 다음 백테스트 탭으로 이동하여 백테스트 작업 기간을 지정하고 백테스트를 시작합니다.

백테스트 프로세스가 완료되면 거래를 검사할 수 있습니다. 각 거래가 진입되기 직전에 진입 조건이 충족되는 것을 확인할 수 있습니다.

전략의 성공적인 자동화를 통해 cBot을 사용하여 우리를 대신하여 거래를 수행할 수 있습니다.

RSI 반전 전략 구현

두 번째 예제에서는 Relative Strength Index (RSI) 지표 반전을 기반으로 한 전략을 구현하려고 합니다. 이 전략에서는 RSI가 방향을 반전할 것으로 예상하고 다음 규칙에 따라 포지션을 진입합니다:

  • RSI 값이 RSI 매수 임계값 아래로 이동하면 매수 포지션을 진입합니다.
  • RSI 값이 RSI 매도 임계값 위로 이동하면 매도 포지션을 진입합니다.

새로운 cBot을 생성하고 이름으로 RSI Reversal Strategy를 입력한 후 생성를 클릭하세요.

코드 편집기가 나타나면 코드 상단에 System.Linq를 참조로 추가하세요.

1
using System.Linq;

cBot을 실행하기 전에 임계값을 수정할 수 있는 두 가지 매개 변수를 추가하겠습니다.

1
2
3
4
5
[Parameter(DefaultValue = 30)]
public int BuyLevel { get; set; }

[Parameter(DefaultValue = 70)]
public int SellLevel { get; set; }

상대 강도 지표를 선언하고 초기화합니다.

1
2
3
4
5
6
private RelativeStrengthIndex _rsi;

protected override void OnStart()
{
    _rsi = Indicators.RelativeStrengthIndex(Bars.ClosePrices, 14);
}
1
2
3
class RSIReversalStrategy():
    def on_start(self):
        self._rsi = api.Indicators.RelativeStrengthIndex(api.Bars.ClosePrices, 14)

그런 다음 우리의 트레이딩 로직을 정의하는 조건을 구현합니다.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
protected override void OnBarClosed()
{

    if (_rsi.Result.LastValue < BuyLevel)
    {
        if (Positions.Count == 0)
            ExecuteMarketOrder(TradeType.Buy, SymbolName, 1000);
        foreach (var position in Positions.Where(p => p.TradeType == TradeType.Sell))
        {
            position.Close();
        }

    }
    else if (_rsi.Result.LastValue > SellLevel)
    {
        if (Positions.Count == 0)
            ExecuteMarketOrder(TradeType.Sell, SymbolName, 1000);
        foreach (var position in Positions.Where(p => p.TradeType == TradeType.Buy))
        {
            position.Close();
        }
    }

}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
def on_bar_closed(self):
    rsi_value = self._rsi.Result.LastValue

    if rsi_value < api.BuyLevel:
        if api.Positions.Count == 0:
            api.ExecuteMarketOrder(TradeType.Buy, api.SymbolName, 1000)
        for position in api.Positions:
            if position.TradeType == TradeType.Sell:
                position.Close()

    elif rsi_value > api.SellLevel:
        if api.Positions.Count == 0:
            api.ExecuteMarketOrder(TradeType.Sell, api.SymbolName, 1000)
        for position in api.Positions:
            if position.TradeType == TradeType.Buy:
                position.Close()

아래에서 전체 코드를 복사할 수 있습니다:

 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
using System;
using System.Linq;
using cAlgo.API;
using cAlgo.API.Collections;
using cAlgo.API.Indicators;
using cAlgo.API.Internals;

namespace cAlgo.Robots
{
    [Robot(AccessRights = AccessRights.None, AddIndicators = true)]
    public class RSIReversalStrategy : Robot
    {
        [Parameter(DefaultValue = 30)]
        public int BuyLevel { get; set; }

        [Parameter(DefaultValue = 70)]
        public int SellLevel { get; set; }

        private RelativeStrengthIndex _rsi;

        protected override void OnStart()
        {
            _rsi = Indicators.RelativeStrengthIndex(Bars.ClosePrices, 14);
        }

        protected override void OnBarClosed()
        {

            if (_rsi.Result.LastValue < BuyLevel)
            {
                if (Positions.Count == 0)
                    ExecuteMarketOrder(TradeType.Buy, SymbolName, 1000);
                foreach (var position in Positions.Where(p => p.TradeType == TradeType.Sell))
                {
                    position.Close();
                }

            }
            else if (_rsi.Result.LastValue > SellLevel)
            {
                if (Positions.Count == 0)
                    ExecuteMarketOrder(TradeType.Sell, SymbolName, 1000);
                foreach (var position in Positions.Where(p => p.TradeType == TradeType.Buy))
                {
                    position.Close();
                }
            }

        }

        protected override void OnStop()
        {

        }
    }
}
 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
import clr
clr.AddReference("cAlgo.API")
from cAlgo.API import *
from robot_wrapper import *

class RSIReversalStrategy():
    def on_start(self):
        self._rsi = api.Indicators.RelativeStrengthIndex(api.Bars.ClosePrices, 14)

    def on_bar_closed(self):
        rsi_value = self._rsi.Result.LastValue

        if rsi_value < api.BuyLevel:
            if api.Positions.Count == 0:
                api.ExecuteMarketOrder(TradeType.Buy, api.SymbolName, 1000)
            for position in api.Positions:
                if position.TradeType == TradeType.Sell:
                    position.Close()

        elif rsi_value > api.SellLevel:
            if api.Positions.Count == 0:
                api.ExecuteMarketOrder(TradeType.Sell, api.SymbolName, 1000)
            for position in api.Positions:
                if position.TradeType == TradeType.Buy:
                    position.Close()

    def on_stop(self):
        pass

이전 전략과 마찬가지로 전략을 빌드하고 인스턴스를 추가한 후 백테스트를 실행합니다.

거래가 진입되기 직전에 진입 조건이 충족되는 것을 다시 확인할 수 있습니다.

이 글에서는 수동 전략을 식별하고 알고리즘 트레이딩 작업을 가능하게 하는 자동화된 전략으로 변환하는 방법을 설명했습니다.

Image title