개요
매매하시는 분들은 보는 관점에 따라 또는 시장상황에 따라 달라지는 Factor를 바로 적용할 수 있는 전략을 구축하고자 합니다. GOM은 고수Plus의 시세/계좌/챠트등 내부데이타를 제공함으로써 자신만의 노하우를 담은 전략만들어 주문을 낼 수 있도록 도구를 지원하자는 취지에서 만들어 졌습니다. COM을 모른다고 GOM을 사용하지 못하는 것은 아닙니다. 물론 기본지식을 가지고 있다면 더 좋겠지만 기본적으로는 COM이든 COM을 기반으로 만든 GOM이든 컴포넌트의 개념상으로는 사용법만 알면 쓸 수 있게 만드는 것입니다. 개념적인 이해가 힘들더라도 사용법을 익힌다는 개념으로 따라오시고 따라하기등의 예제를 통해 실제로 작성하시면서 연습하시면 됩니다.
GOM 구조 이해하기
GOM의 구조를 이해하기에 앞서 GOM 전체 구조를 눈에 익혀 봅니다.

GOM 구조보기

고수의 공개된 객체들 즉 GOM은 위의 그림처럼 트리구조로 구조화되어 있습니다. GxServer를 최상위객체로 하여 그 아래로 크게는 GxSymbolStore, GxTradeStore, GxChartStore가 있고 각각의 하위구조를 갖고 있습니다. 이 구조를 눈에 익혀야 하는 이유는 다음과 같습니다. 예를 들어 계좌의 예탁금을 알고 싶다면 GxServer 객체를 얻은 후 이를 통해 이 객체의 GxTradeStore를 얻을 수 있고 다음으로 GxAccounts와 GxAccount의 객체에 접근하여 해당되는 계좌의 예탁금을 비롯하여 증거금, 주문가능금액등을 가져올 수 있음을 알기 위해서 입니다. 아래의 코드상으로 이해를 해보면 ⓐ,ⓑ,ⓒ 객체를 담을 변수를 선언하고 GetObject함수로 GOM에 연결하여 계좌정보를 가지고 오는 코드로 간단하게 작성할 수 있습니다. 이렇듯 GOM에 대한 트리구조를 보시면서 계좌정보를 원한다면 GxTradeStore에게 정보를 달라고 하면 되겠구나를 이해하시면 됩니다.

Option Explicit
Public mobjServer As GxServer --- ⓐ 'GOM 서버의 Root Object와 연결할 객체
Public mobjTradeStore As GxTradeStore --- ⓑ 'TradeStore와 연결할 객체

Private Sub cmdExcute_Click()
Dim objAccount As GxAccount --- ⓒ' 계좌를 담을 객체

On Error GoTo DoFail
Set mobjServer = GetObject(, "P2.GxServer") 'GOM 서버의 Root Object 연결
Set mobjTradeStore = mobjServer.TradeStore 'TradeStore를 연결시켜준다.

GoTo DoSuccess
Exit Sub

'서버 연결 실패시 메세지 출력후 끝냄
DoFail:
MsgBox "서버와 연결하는데 실패 하였습니다"
Exit Sub

DoSuccess: 'Combo Box 초기화
cboAccount.Clear
'TradeStore의 계좌목록을 Combo Box에 넣어준다.
For Each objAccount In mobjServer.TradeStore.Accounts
cboAccount.AddItem objAccount.Code
Next

'기본적으로 첫번째 계좌를 선택합니다.
If cboAccount.ListCount > 0 Then
cboAccount.ListIndex = 0
End If
End Sub
Private Sub cmdStop_Click()
mobjServer = Nothing
End Sub

이와 같은 객체간의 관계를 이해해야 하는 것은 GOM을 이용하는데 필수적입니다.

GOM 객체의 구성요소
GOM의 객체에는 속성(property)과 메소드(method) 그리고 이벤트(Event)로 구성되어 있습니다.

속성은 말그대로 객체의 속성을 의미하고 메소드는 객체가 어떠한 행동을 수행하게 하는 함수입니다. 또한 이벤트는 어떠한 상황이 발생되면 알려주는 기능을 합니다. 예를 들어 GxChartData 객체에는 서버로부터 챠트데이타를 요청하는 Define이라는 메소드가 있습니다. 이 Define 함수를 선물최근월물 1분봉을 100개 가지고 와라하고 호출하면 Define함수는 Symbol, Base, Period등의 속성값들을 변경하고 서버에 데이타를 달라고 요청을 하고는 제 할일을 마칩니다. GOM서버 즉 고수Plus에서는 Define의 요청을 받고 데이타를 수집하여 마침내 클라이언트에게 전달합니다. 이 때 GxChartData 객체에서는 챠트데이타가 서버로부터 도착했다라고 OnDatarefreshed라는 이벤트가 발생하게 됩니다. Define함수로 서버에 요청을 했던 클라이언트는 왔구나하고는 인지하고는 챠트자료가 준비되었다라는 Ready속성을 True로 만들고 챠트 그림을 그리게 해야지 또는 파일에 저장해야지를 작성하게 됩니다.

GOM 구조도를 보면 GxChartData를 사용하기 위해 GxChartStore 객체를 얻어야하므로 아래와 같이 선언하는 예입니다.
Option Explicit
'GOM Server 연결 Object
Public mobjServer As GxServer

'GxChartStore 연결 Object
Public mobjChartStore As GxChartStore

다음과 같이 이벤트 구독을 위해 준비하는 예입니다. 이벤트구독을 위한 자세한 절차는 따라하기의 챠트부분을 참조하시기 바랍니다.
Option Explicit

'여러개의 종목들에 대해 챠트 데이타의 Event를 받기 위해서 클래스로 만들어주었다.
Public WithEvents mobjChartSink As GxChartData
GOM의 최상위객체 얻기
MS-Excel 의 경우 사용자는 WorkSheet 객체의 하위 인터페이스를 바로 얻을 수 없고 최상위 인터페이스를 통하여 하위 객체 인터페이스를 얻습니다. 이와 같이 GOM 객체를 사용하려면 꼭 최상위 객체의 인터페이스인 IGxServer를 얻어야 합니다.

이 최상위객체를 얻기 위해서는 여러가지 방법이 있을 수 있습니다. 앞서 말씀드렸듯이 GOM은 초기바인딩(Early binding)과 후기바인딩(Late binding)을 모두 사용할 수 있는 Dual Interface를 지원합니다. 이 말은 개념적으로는 type을 프로그램 링크하는 단계에서 확정하는 방법과 실행시 타입결정을 한다는 의미이지만 사용법관점으로만 이해한다면 GOM의 객체를 얻기 위해서 타입라리브러리를 import하여 최상위객체를 얻는 방법과 VB에서의 CreateObject GetObject, 델파이의 CreateOleObject GetActiveOleObject, MFC의 CreateDispatch, WinAPI GetActiveObject등을 통하여 최상위객체를 얻는 두가지 방법을 모두 지원한다는 뜻입니다.

Type Library로 최상위객체 얻기
 

TypeLibrary Import 하기
먼저 인터페이스의 타입들의 명세서인 p2.tlb파일을 import해야만 인터페이스를 참조할 수 있습니다.
tlb파일을 import 하는 방법은 개발툴(Visual C++, Visual basic, Delphi...)마다 다르므로 객 개발툴의 도움말을 참조하시거나 [공유하기]-[각 개발언어의 클라이언트] 만들기 도움말을 참조하시면 됩니다.

Delphi Sample
var
i : Integer;
aAccount : IGxAccount;
aGxServer : TGxServer;
aGxTradeStore : IGxTradeStore;
aGxAccounts : IGxAccounts;
begin
aGxServer := TGxServer.Create(Self);
aGxTradeStore := aGxServer.TradeStore as IGxTradeStore;

aGxAccounts := aGxTradeStore.Accounts as IGxAccounts;

for i:=1 to aGxAccounts.Count do
begin
aAccount := aGxAccounts[i] as IGxAccount;
Memo1.Lines.Add('early : ' + aAccount.Code);
end;
end;

IDispatch Type의 최상위객체 얻기
 

PROGID
GOM Server는 Windows의 시스템 레지스트리에 모든 GOM class들을 등록 합니다. 각각의 GOM class는 GUID라는 class 식별자를 가집니다. 이를 CLSID 이라 합니다. 레지스트리에는 각각의 CLSID가 프로그래밍적인 식별자인 PROGID 와 연결되어 있습니다. GOM 사용자는 PROGID를 사용하여 GOM의 최상위 Object를 생성하거나 얻을 수 있습니다. GOM 최상위 Object의 PROGID는 'P2.GxServer' 이며 VB에서의 CreateObject GetObject, 델파이의 CreateOleObject GetActiveOleObject, MFC의 CreateDispatch, WinAPI GetActiveObject등에서 이를 PROGID를 사용 합니다.

Delphi Sample
var
i : Integer;
stmsg : string;
aGxServer, aAccounts, aAccount : Variant;
begin
try
aGxServer := GetActiveOleObject('P2.GxServer');
except
aGxServer := CreateOleObject('P2.GxServer');
end;

aAccounts := aGxServer.TradeStore.Accounts;
for i:=1 to aAccounts.Count do
begin
aAccount := aAccounts.Item[i];
Memo1.Lines.Add('late : ' + aAccount.Code);
end;
end;

대부분의 GOM 객체는 최상위객체를 생성하는 단계에서 같이 생성이 되어집니다. GxTradeStore와 GxTradeStore, GxSymbolStore, GxServerInfo를 포함하여 Collection객체의 경우는 자동 생성됩니다. 그리고 프로그램 종료 시까지 새로 추가되거나 제거 되지 않습니다.

Collection의 구성원이 되는 객체의 경우는 필요시마다 생성 시킬 수 있습니다. 예를 들어 사용자가 새롭게 주문을 낼 경우 GxOrder, GxConfirm, GxFill Object등이 GxOrders, GxConfirms, GxFills등 Collection 객체에 추가됩니다. 이는 사용자가 직접적으로 수행할 수 없고 주문을 통해서 간접적으로 생성 시킬 수 있습니다.

GxTradeStore 의 하위 GxOrderHandler Object의 경우는 IGxOrderHandler의 PutNewOrder, PutChangeOrder, PutCancelOrder등의 메소드를 통해 GxOrderHandler 하위의 GxOrderReqs Collection Object에 GxOrderReq Object를 간접 생성 시킬 수 있습니다.

GxChartStore Collection Object도 GxOrderHandler와 비슷하게 IGxChartStore의 Add 메소드를 통해 새롭게 GxChartData Object 를 생성 시킬 수 있고 Remove, RemoveByKey 등의 메소드를 통해 GxChartData Object 등을 제거 할 수도 있습니다.
Collection 객체 사용하기
Collection 객체는 구성원들을 여러개 가지고 있는 집합객체를 말합니다. GOM의 전체구조도를 보시면 초록색으로 표시한 객체들은 Collection객체입니다. 이는 기차를 연상해보시면 됩니다. 기차 한대에 1호차, 2호차...10호차까지 연결되어 있습니다. 특실도 있고 식당칸도 있고 일반실과 같이 속성은 좀 다르겠지만 기차 한칸의 공간적인 의미는 같습니다. 이렇듯 챠트 데이터를 관리하는 GxChartStore경우 1번 GxChartData, 2번 GxChartData ...n번 GxChartData를 가지고 있습니다.

Automation에서의 Collection Object 권고사항은 IEnumVariant 인터페이스를 구현하며 Add, Remove 메소드가 존재하며 _NewEnum, Item, Count 프로퍼티가 존재 해야 한다는 것입니다. 모든 GOM Collection 객체는 _NewEnum, Item, Count를 지원하며 이를 통해 VB, VBA 등에서 For - Each 문, 다른 언어에서도 for 문을 이용하여 이 집합체의 객체들을 모조리 조회할 수 있습니다. 그러나 Add, Remove 함수의 경우는 GxChartStore에서만 구현되어있습니다. 이 Collection객체의 속성들을 살펴보면 _NewEnum은 Enumeration 인터페이스인 IEnumVariant를 얻을 수 있는 속성입니다. 이는 Collection과 같은 형태의 객체는 표준화된 인터페이스를 지원하도록 되어있는데 이를 지원하는 속성이라고 보시면 됩니다. Count속성은 기차에 몇호차까지 있는지를 알 수 있는 속성입니다. 이처럼 Collection에 몇개의 구성원이 있는지를 알려줍니다. 다음으로 Item 속성은 Collection에 포함되어 있는 개별구성원의 인터페이스를 반환합니다. 기차로 다시 설명하자면 Item[1]하면 1호차의 객체인터페이스를 Item[2]는 2호차의 객체인터페이스를 반환합니다.

Item 프로퍼티에 입력 파라미터는 Variant 타입이므로 여러 타입의 입력이 가능합니다만 GOM의 모든 Collection 객체마다 허용되는 타입이 지정되어 있습니다. 모든 GOM Collection 객체는 long type을 지원하는데 long 입력값번째의 인터페이스를 반환할 때 사용됩니다. long 타입의 경우 1 ~ (Collection 자체의 'Count' 프로퍼티값)까지 입력해야 합니다. 해당하지 않은 형식을 입력하거나 범위를 벗어나면 NULL이 반환 되므로 주의 하여야 합니다. 또한 예외로 GxSymbolStore의 경우는 long 타입이외에도 BSTR 형식도 지원합니다. Item 파라미터에 "10146"을 입력할 경우 Code 가 "10146"인 GxSymbol의 IGxSymbol 인터페이스를 반환합니다. GxStrikePrices의 경우도 long 값이외에 double값을 지원합니다. Item 파라미터에 120.50 을 입력할 경우 행사가가 120.50 인 IGxStrikePrice을 반환합니다. 그리고 Item 프로퍼티는 기본 속성 이므로 VB의 경우 SymbolStore.Item("10146")대신 SymbolStore("10146")으로 사용 가능합니다. 이 기본 속성은 다른 Language 에서도 이용하여 코드를 간결하게 할 수 있습니다.

var
i : Integer;
aAccount : IGxAccount;
aGxServer : TGxServer;
aGxTradeStore : IGxTradeStore;
aGxAccounts : IGxAccounts; --- ' Collection 객체
begin
aGxServer := TGxServer.Create(Self);
aGxTradeStore := aGxServer.TradeStore as IGxTradeStore;

aGxAccounts := aGxTradeStore.Accounts as IGxAccounts;
for i:=1 to aGxAccounts.Count do --- ' 1~count만큼 item가지고 오기
begin
' aGxAccount.item[i]를 간결하게 표현
aAccount := aGxAccounts[i] as IGxAccount;
Memo1.Lines.Add('early : ' + aAccount.Code);
end;
end;
IDispatch형 속성 사용하기
속성에는 보통 long(정수), double(실수), BSTR(문자열)등 일반 데이터형이지만 객체가 속성이 되는 경우도 있습니다.
이때 객체속성의 경우는 IDispatch형으로 제공되므로 실제 인터페이스 타입으로 형변환하여 사용하셔야 합니다.

예를 들어 위의 GxPosition 객체를 사용하여 어떤 미결제약정에 해당하는 계좌의 증거금을 알고자 할 때 Account 속성을 참고하여 IGxAccount를 얻은 후 IGxAccount의 증거금 속성을 호출해야 합니다. 이 때 GxPosition 속성중 Account의 IDispatch 속성을 IGxAccount 타입으로 형변환하여 계좌의 증거금을 사용합니다.

다음은 델파이의 예입니다.
var
aGxAccount : IGxAccount;
begin
aGxAccount := FGxPosition.Account as IGxAccount;
Edit1.Text := Format('%n', [aGxAccount.Margin]);
end;
이벤트 수신하기
GOM 객체의 일부는 Client에 이벤트를 발생 시킵니다. 이와 같은 객체를 Connectable Object라고 부릅니다. GOM구조도에서 테두리가 빨간색으로 표시된 객체들은 이벤트 수신을 할 수 있습니다. 서버에서 참조하는 값이 변할 경우 클라이언트에 이벤트를 발생시킵니다. 클라이언트는 이벤트를 받아 이벤트의 종류에 따라 자신이 추적하고 있는 값(예:A종목의 현재가)을 갱신합니다.

클라이언트가 A종목의 현재가를 화면에 실시간으로 표시한다면 클라이언트는 A종목의 인터페이스를 찾아 현재가 속성을 호출하고 이에 대한 종목 현재가 이벤트를 요청합니다. 그 이후 서버로 부터 현재가 변경 이벤트를 수신하면 수신 시점으로 다시 A종목의 인터페이스를 통해 다시 현재가 속성을 읽습니다.

클라이언트는 이벤트를 수신하기 위해서 이벤트 수신 대상 객체인 EventSink 객체를 만들어야 합니다. 그리고 그 전에 서버에게 이벤트 요청을 해야 합니다. EventSink를 제작, Event 요청 방법은 각 Lanuage 마다 틀리므로 Language 별 클라이언트 제작 시 이를 다시 다룹니다.
GxServerInfo 사용하기

클라이언트가 COM Server 즉 고수Plus 서버와의 연결상태등을 알기 위해서는 GxServerInfo 객체를 사용해야 합니다. GxServerInfo 객체를 사용하기 위한 기본 인터페이스는 IGxServerInfo 이고 'GOM 구조도'를 보면 GxServerInfo 객체는 최상위객체의 한 단계 아래의 객체입니다. IGxServerInfo 인터페이스는 최상위 IGxServer에 'ServerInfo' 프로퍼티 호출을 통해 얻을 수 있습니다. IGxServerInfo 의 인터페이스를 얻은 후 IGxServerInfo 의 ServerDate 등의 프로퍼티를 사용할 수 있습니다.