콘텐츠로 이동

차트 객체 및 그림

차트 객체(그림)는 cTrader 차트에 선 또는 기하학적 모양을 그릴 수 있도록 합니다. 이를 사용하여 cBot 또는 지표 데이터를 기반으로 차트에 패턴을 그리거나 특정 이벤트를 표시할 수 있습니다.

차트 객체는 위치 지정을 위해 X 및 Y 좌표를 사용합니다.

  • X축은 차트 시간 또는 바 인덱스를 나타냅니다.
  • Y축은 심벌 가격입니다.

모든 차트 객체는 ChartObject 기본 클래스에서 파생되며, 이는 모든 차트 객체가 특정 기본 기능을 상속받음을 의미합니다.

차트 객체 코드 샘플

지표 창 내부에 그리기

차트 객체를 생성할 때 메인 심벌 차트에만 국한되지 않습니다. 사실, 지표 출력을 포함하는 모든 창 내부에 차트 객체를 그릴 수 있습니다.

Chart 클래스에는 IndicatorAreas 컬렉션이 있습니다. 이 컬렉션은 지표가 출력을 표시할 수 있는 모든 비오버레이 또는 별도의 창을 포함합니다.

또한 Indicator 클래스의 IndicatorArea 속성을 사용하여 현재 지표 영역에 접근할 수 있습니다.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
using cAlgo.API;

namespace NewIndicator
{
    [Indicator(IsOverlay = false, AccessRights = AccessRights.None)]
    public class NewIndicator : Indicator
    {
        protected override void Initialize()
        {
            var verticalLine = IndicatorArea.DrawVerticalLine("line", Chart.LastVisibleBarIndex, Color.Red);
        }

        public override void Calculate(int index)
        {
        }
    }
}

위 지표의 인스턴스를 실행하면 별도의 지표 창에 빨간색 선이 표시됩니다. 별도의 지표 영역에 차트를 생성할 때, ChartIndicatorArea 모두 ChartArea 기본 클래스에서 상속받으므로 모든 그리기 방법을 사용할 수 있습니다.

정적 텍스트

정적 텍스트는 위치 지정을 위해 X 및 Y 좌표 대신 정적 수평 및 수직 정렬을 사용합니다. 정적 텍스트를 표시하거나 그리려면 DrawStaticText() 메서드를 사용하십시오.

1
var staticText = Chart.DrawStaticText("static", "This is the text that will be shown", VerticalAlignment.Center, HorizontalAlignment.Center, Color.Red);

이 차트 객체를 지표에 연결하고 인스턴스를 실행하면 메인 차트에 다음 텍스트가 표시됩니다.

Image title

수직선

수직선을 그리려면 DrawVerticalLine() 메서드를 사용하세요.

1
2
3
var verticalLine = Chart.DrawVerticalLine("line", Chart.LastVisibleBarIndex, Color.Red);
// Or
var verticalLine = Chart.DrawVerticalLine("line", Bars.OpenTimes[Chart.LastVisibleBarIndex], Color.Red);

수평선

수평선을 그리려면 DrawHorizontalLine() 메서드를 사용하세요.

1
2
3
/* We use the maximum of the high prices
of the last ten bars as the Y coordinate. */ 
var horizontalLine = Chart.DrawHorizontalLine("line", Bars.HighPrices.Maximum(10), Color.Red);

추세선

추세선은 차트의 특정 지점에서 시작하여 다른 지점에서 끝납니다. 추세선은 다양한 모양이나 복잡한 패턴을 만드는 데 유용합니다.

추세선을 그리려면 DrawTrendLine() 메서드를 사용하세요.

1
2
3
4
5
6
7
/* We draw a line from the low price
 of the first visible bar to the high price
 of the last visible bar on the chart. */
var trendLine = Chart.DrawTrendLine("line", Chart.FirstVisibleBarIndex, Bars.LowPrices[Chart.FirstVisibleBarIndex], Chart.LastVisibleBarIndex, Bars.HighPrices[Chart.LastVisibleBarIndex], Color.Red);

// Alternatively, consider the following.
var trendLine = Chart.DrawTrendLine("line", Bars.OpenTimes[Chart.FirstVisibleBarIndex], Bars.LowPrices[Chart.FirstVisibleBarIndex], Bars.OpenTimes[Chart.LastVisibleBarIndex], Bars.HighPrices[Chart.LastVisibleBarIndex], Color.Red);

직사각형

직사각형을 그리려면 DrawRectangle() 메서드를 사용하세요.

1
2
3
4
5
6
7
var rectangle = Chart.DrawRectangle("rectangle", Chart.FirstVisibleBarIndex + 1, Bars.LowPrices[Chart.FirstVisibleBarIndex + 1], Chart.LastVisibleBarIndex, Bars.HighPrices[Chart.LastVisibleBarIndex], Color.Red);

/* We fill the rectangle with a transparent color.
By using its current color, we only change the alpha
channel. */
rectangle.IsFilled = true;
rectangle.Color = Color.FromArgb(80, rectangle.Color);

삼각형

삼각형을 그리려면 DrawTriangle() 메서드를 사용하세요.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
var middleX = Chart.FirstVisibleBarIndex + (Chart.LastVisibleBarIndex - Chart.FirstVisibleBarIndex) / 2;
var middleY = Bars.LowPrices[Chart.FirstVisibleBarIndex] + (Bars.HighPrices[Chart.LastVisibleBarIndex] - Bars.LowPrices[Chart.FirstVisibleBarIndex]) / 2;

var triangle = Chart.DrawTriangle("triangle", Chart.FirstVisibleBarIndex, Bars.LowPrices[Chart.FirstVisibleBarIndex], middleX, middleY, Chart.LastVisibleBarIndex, Bars.LowPrices[Chart.FirstVisibleBarIndex], Color.Red);

// We fill the triangle with a transparent color
// by using it's current color, we change only the alpha channel

/* We fill the triangle with a transparent color.
By using its current color, we only change the alpha
channel. */
triangle.IsFilled = true;
triangle.Color = Color.FromArgb(80, triangle.Color);

기타 차트 객체

간결함을 위해 위의 코드 스니펫에서는 여러 다른 차트 객체를 언급하지 않았습니다. 이러한 객체에는 다음이 포함되지만 이에 국한되지 않습니다:

  • 타원
  • 아이콘
  • 앤드류스 피치포크
  • 등거리 채널
  • 피보나치 확장
  • 피보나치 팬
  • 피보나치 되돌림

이러한 모든 객체는 유사한 매개변수를 받는 Draw...() 메서드를 사용하여 그릴 수 있습니다.

위험-보상

ChartRiskReward 인터페이스는 차트에서 위험-보상 객체를 프로그래밍 방식으로 생성하고 관리할 수 있는 타입을 제공합니다.

아래 코드는 위험-보상 객체를 그리는 지표를 생성하는 방법을 보여줍니다:

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

namespace cAlgo
{
    [Indicator(AccessRights = AccessRights.None, IsOverlay = true)]
    public class SimpleRiskReward : Indicator
    {
        protected override void Initialize()
        {
            var type = new ChartRiskRewardFixedRiskType(
                ChartRiskRewardAmountType.BalancePercentage, 
                1                                            
            );
            var tradeType = TradeType.Buy;
            var orderType = OrderType.Market;

            var entryPrice = Chart.Bars.LastBar.Close;
            var time1 = Chart.LastVisibleBarIndex - 20; 
            var time2 = Chart.LastVisibleBarIndex;      

            var rr = Chart.DrawRiskReward(
                "SimpleRR",     
                time1,           
                time2,            
                entryPrice,       
                orderType,        
                tradeType,        
                type              
            );

            rr.IsInteractive = true;

            rr.RiskColor = Color.Yellow;
            rr.RiskLineStyle = LineStyle.DotsRare;
            rr.RiskThickness = 3;

            rr.RewardColor = Color.Blue;
            rr.RewardLineStyle = LineStyle.LinesDots;
            rr.RewardThickness = 2;

            PrintRRInfo(rr);
        }

        private void PrintRRInfo(ChartRiskReward rr)
        {
            Print($"Name: {rr.Name} | Type: {rr.Type.GetType().Name} | Order Type: {rr.OrderType} | Trade Type: {rr.TradeType} | Time 1: {rr.Time1:o} | Time 2: {rr.Time2:o} | Entry: {rr.EntryPrice} | SL: {rr.StopLossPrice} | TP: {rr.TakeProfitPrice} | RR: {rr.RiskRewardRatio} | Volume: {rr.VolumeInUnits}");
        }

        public override void Calculate(int index)
        {
        }
    }
}

주요 객체 설정

차트 객체 이름 지정

차트 객체를 그릴 때마다 그리기 메서드에 객체 이름을 인수로 제공해야 합니다.

모든 차트 객체 이름은 고유해야 합니다. 이 요구 사항이 충족되지 않으면 실행 시간에 따라 동일한 이름의 차트 객체가 다른 객체를 덮어쓸 위험이 있습니다. 현재 바 인덱스 값이나 현재 시간을 사용하여 각 객체에 대해 고유한 이름을 생성할 수 있습니다.

차트 객체 접근

모든 차트 객체는 Objects 컬렉션에 포함되어 있습니다. 이 컬렉션에는 사용자가 그린 객체도 포함됩니다. 결과적으로 Objects 컬렉션에 접근하여 차트에서 객체를 제거하거나 속성을 수정할 수 있습니다.

아래 예제는 Objects 컬렉션의 멤버에 접근하는 방법을 보여줍니다:

 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
using cAlgo.API;
using System.Linq;
namespace NewIndicator
{
    [Indicator(IsOverlay = true, AccessRights = AccessRights.None)]
    public class NewIndicator : Indicator
    {
        protected override void Initialize()
        {
            foreach (var chartObject in Chart.Objects)
            {
                /* If the object is a trend line 
                we change its Y1/2 properties */
                if (chartObject is ChartTrendLine trendLine)
                {
                    trendLine.Y1 = Chart.BottomY;
                    trendLine.Y2 = Chart.TopY;
                }
            }

            /* Here, we filter all objects of the 'ChartRectangle'
            type. */
            var rectangles = from chartObject in Chart.Objects
                             where chartObject is ChartRectangle
                             select chartObject as ChartRectangle;

            /* We select only the chart objects with a name that
            begins with "MyObjects". */
            var myObjects = from chartObject in Chart.Objects
                            where chartObject.Name.StartsWith("MyObjects", System.StringComparison.OrdinalIgnoreCase)
                            select chartObject;

            /* We select only interactive objects. If an object
            is interactive, it will not be removed when the 
            indicator is removed or reloaded. */
            var interactiveObjects = from chartObject in Chart.Objects
                                     where chartObject.IsInteractive
                                     select chartObject;

            /* We remove all objects with a name 
            that begins with "ToRemove". */
            var chartObjectsCopy = Chart.Objects.ToArray();

            foreach (var chartObject in chartObjectsCopy)
            {
                if (chartObject.Name.StartsWith("ToRemove", System.StringComparison.OrdinalIgnoreCase))
                {
                    /* Chart 'RemoveObject' gets the object name
                    as a parameter. */
                    Chart.RemoveObject(chartObject.Name);
                }

            }
        }

        public override void Calculate(int index)
        {
        }
    }
}

이벤트

차트 객체에는 객체가 그려지거나 업데이트되거나 제거될 때 알 수 있는 여러 이벤트가 있습니다:

  • ObjectsAdded - 하나 이상의 차트 객체가 차트에 추가될 때 트리거됩니다.
  • ObjectsRemoved - 하나 이상의 차트 객체가 차트에서 제거될 때 트리거됩니다.
  • ObjectsUpdated - 하나 이상의 차트 객체가 업데이트될 때 트리거됩니다 (사용자나 활성 지표 또는 cBot에 의해 속성이 변경됨).
  • ObjectsSelectionChanged - 사용자가 하나 이상의 차트 객체를 선택할 때 트리거됩니다.
  • ObjectHoverChanged - 마우스 커서가 차트 객체 위에 올라갈 때 트리거됩니다.

다음 예제는 이 다섯 가지 이벤트 유형을 모두 사용합니다:

 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
using cAlgo.API;

namespace NewIndicator
{
    [Indicator(IsOverlay = true, AccessRights = AccessRights.None)]
    public class NewIndicator : Indicator
    {
        protected override void Initialize()
        {
            Chart.ObjectsAdded += Chart_ObjectsAdded;
            Chart.ObjectsRemoved += Chart_ObjectsRemoved;
            Chart.ObjectsUpdated += Chart_ObjectsUpdated;
            Chart.ObjectsSelectionChanged += Chart_ObjectsSelectionChanged;
            Chart.ObjectHoverChanged += Chart_ObjectHoverChanged;
        }

        private void Chart_ObjectHoverChanged(ChartObjectHoverChangedEventArgs obj) => throw new System.NotImplementedException();

        private void Chart_ObjectsSelectionChanged(ChartObjectsSelectionChangedEventArgs obj) => throw new System.NotImplementedException();

        private void Chart_ObjectsUpdated(ChartObjectsUpdatedEventArgs obj) => throw new System.NotImplementedException();

        private void Chart_ObjectsRemoved(ChartObjectsRemovedEventArgs obj) => throw new System.NotImplementedException();

        private void Chart_ObjectsAdded(ChartObjectsAddedEventArgs obj) => throw new System.NotImplementedException();

        public override void Calculate(int index)
        {
        }
    }
}

인터랙티브 및 비인터랙티브 객체

인터랙티브 객체를 작업할 때 사용자는 객체 위치, 색상, 코멘트 등과 같은 속성을 변경할 수 있습니다. 모든 사용자 그린 객체는 기본적으로 인터랙티브입니다.

참고

ChartStaticText 속성은 관련 객체가 인터랙티브인지 여부에 관계없이 변경할 수 없습니다.

객체를 인터랙티브로 만들려면 IsInteractive 속성을 true로 설정하세요:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
using cAlgo.API;

namespace NewIndicator
{
    [Indicator(IsOverlay = true, AccessRights = AccessRights.None)]
    public class NewIndicator : Indicator
    {
        protected override void Initialize()
        {
            var verticalLine = Chart.DrawVerticalLine("line", Chart.LastVisibleBarIndex, Color.Red);

            verticalLine.IsInteractive = true;
        }

        public override void Calculate(int index)
        {
        }
    }
}

모든 차트 객체에는 IsInteractive 속성이 있습니다. 기본값은 false입니다.

차트 객체가 인터랙티브인 경우, 지표 또는 cBot 인스턴스가 제거되거나 중지될 때 제거되지 않습니다. 반대로 비인터랙티브 객체는 지표 또는 cBot이 작동을 멈추면 자동으로 제거됩니다.

혼란을 피하기 위해 관련 인스턴스가 제거된 후 인터랙티브 객체를 정리하려면 지표 Destroy 또는 cBot OnStop 메서드를 사용하세요.

차트 객체가 인터랙티브하지 않으면 차트 객체 목록 및 컬렉션에서도 보이지 않습니다.

잠금 및 잠금 해제된 객체

차트 객체를 잠그면 사용자가 수정하거나 업데이트할 수 없습니다. Trader (차트 속성) 상자를 통해 또는 IsLocked 속성을 true로 설정하여 이를 수행할 수 있습니다. 기본값은 false입니다.

객체를 인터랙티브로 만들면서 동시에 사용자가 업데이트하지 못하도록 잠금을 사용할 수 있습니다. 다음 예제는 수직선 객체를 잠급니다:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
using cAlgo.API;

namespace NewIndicator
{
    [Indicator(IsOverlay = true, AccessRights = AccessRights.None)]
    public class NewIndicator : Indicator
    {
        protected override void Initialize()
        {
            var verticalLine = Chart.DrawVerticalLine("line", Chart.LastVisibleBarIndex, Color.Red);

            verticalLine.IsLocked = true;
        }

        public override void Calculate(int index)
        {
        }
    }
}

표시 및 숨기기

차트에 객체를 그린 후 숨길 수 있습니다. 객체는 여전히 차트에 존재하지만 완전히 보이지 않게 됩니다.

이를 위해 IsHidden 속성을 true로 설정하세요.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
using cAlgo.API;

namespace NewIndicator
{
    [Indicator(IsOverlay = true, AccessRights = AccessRights.None)]
    public class NewIndicator : Indicator
    {
        protected override void Initialize()
        {
            var verticalLine = Chart.DrawVerticalLine("line", Chart.LastVisibleBarIndex, Color.Red);

            verticalLine.IsHidden = true;
        }

        public override void Calculate(int index)
        {
        }
    }
}

리소스 사용량은 이 기능을 사용하는 주요 고려 사항입니다. 차트에 자주 나타나야 하지만 항상 그렇지는 않은 객체가 있다면, 매번 제거하고 다시 그리는 대신 숨기는 것이 더 좋습니다.

객체 선택 및 외관 인덱스 (ZIndex)

당연히 차트 상에서 여러 객체가 서로 교차하여 특정 객체를 선택하기 어렵거나 불가능한 경우가 있을 수 있습니다. 교차하는 차트 객체 그룹 위에 마우스 커서를 올리면 가장 마지막에 그려진 객체만 선택할 수 있습니다.

이 동작을 변경하려면 ZIndex 속성을 사용할 수 있습니다. 이는 복잡한 차트 객체 패턴을 표시하려고 할 때 유용할 수 있습니다.

 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
using cAlgo.API;

namespace NewIndicator
{
    [Indicator(IsOverlay = true, AccessRights = AccessRights.None)]
    public class NewIndicator : Indicator
    {
        protected override void Initialize()
        {
            var firstVerticalLine = Chart.DrawVerticalLine("line1", Chart.LastVisibleBarIndex, Color.Red);

            firstVerticalLine.IsInteractive = true;

            var secondVerticalLine = Chart.DrawVerticalLine("line2", Chart.LastVisibleBarIndex, Color.Yellow);

            secondVerticalLine.IsInteractive = true;

            firstVerticalLine.ZIndex = secondVerticalLine.ZIndex + 1;
        }

        public override void Calculate(int index)
        {
        }
    }
}

차트에 첨부되면 위의 지표는 노란색 대신 빨간색 수직선을 표시합니다. 첫 번째 선의 ZIndex 속성 값이 두 번째 선의 해당 값보다 높기 때문에 두 번째 (노란색) 선보다 우선합니다.

즉, ZIndex 속성은 객체가 겹칠 때 어떤 차트 객체가 먼저 표시되는지를 결정합니다. 그려진 모든 차트 객체는 자동으로 ZIndex 속성에 특정 값이 할당됩니다.

객체가 제거되었는지 확인

모든 차트 객체는 ChartObject 기본 클래스에서 IsAlive 속성을 상속받습니다. 이 속성의 값은 객체가 차트에 있는 동안 (보이는지 여부와 관계없이) true입니다. 객체가 차트에서 제거되면 값은 false로 설정됩니다.

차트 객체에 대한 참조를 저장했는데 사용자에 의해 해당 객체가 제거된 경우, IsAlive 속성을 확인하여 객체가 살아있는지 죽었는지 확인할 수 있습니다.

 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
using cAlgo.API;

namespace NewIndicator
{
    [Indicator(IsOverlay = true, AccessRights = AccessRights.None)]
    public class NewIndicator : Indicator
    {
        private ChartVerticalLine _verticalLine;

        protected override void Initialize()
        {
            _verticalLine = Chart.DrawVerticalLine("line1", Chart.LastVisibleBarIndex, Color.Red);
            _verticalLine.IsInteractive = true;

            Chart.ObjectsRemoved += Chart_ObjectsRemoved;

            Print(_verticalLine.IsAlive);
        }

        private void Chart_ObjectsRemoved(ChartObjectsRemovedEventArgs obj)
        {
            Print(_verticalLine.IsAlive);

            /* If the object is removed, we should rid of its
            reference. Otherwise, it will remain in memory. */
            if (_verticalLine.IsAlive is false)
            {
                _verticalLine = null;

                Print("Object reference removed");
            }
        }

        public override void Calculate(int index)
        {
        }
    }
}

이 지표의 인스턴스를 실행하고 빨간 선을 마우스 오른쪽 버튼으로 클릭한 후 제거하세요. 그러면 로그에 "Object reference removed" 메시지가 출력됩니다.

(죽은) 차트 객체에 대한 참조를 유지하면 메모리 누수가 발생합니다. 가비지 컬렉션 중에 객체는 여전히 살아있는 것으로 간주되어 컬렉션 프로세스를 견딜 것입니다.

이 문제를 방지하려면 ObjectsRemoved 이벤트와 IsAlive 속성을 함께 사용하세요.

바 인덱스 또는 시간

차트 객체를 코딩할 때 X축에 대해 차트 시간 또는 바 인덱스를 사용할 수 있습니다.

우리의 의견으로는 차트 시간이 더 나은 옵션입니다. 바 인덱스를 사용할 때는 미래 값을 계획할 수 없으며 (필요한 인덱스가 아직 존재하지 않기 때문에) 바 사이의 공간을 고려할 수 없습니다. 그러나 바 인덱스는 특히 비교적 간단한 차트 객체의 경우 사용하기 더 쉬울 수 있습니다.

모든 Chart.Draw 메서드는 바 인덱스와 차트 시간에 대해 다른 오버로드를 가지고 있습니다.