Git Product home page Git Product logo

cpgo's Introduction

cpgo

=====

cybosplus(증권API) + golang 을 이용하여 투자 분석 및 시스템트레이딩을 할수 있도록 만든 간단한 Wrapper 라이브러리 입니다.

필요한것들

설치

go get github.com/ippoeyeslhw/cpgo

설명

cpgo 는 사이보스플러스를 go언어에서 사용할수 있도록 Wrapping 한 것입니다. go-ole패키지를 기반으로 작성되었습니다.

Import

go-ole패키지를 기반으로 작성되었으므로 많은 부분을 의존합니다. 반드시 임포트하여야합니다.

import (
	ole "github.com/go-ole/go-ole"
	"github.com/ippoeyeslhw/cpgo"
)

프로그램 시작

반드시 cointialize, uncoinitialize 호출 해야합니다.

	ole.CoInitialize(0)
	defer ole.CoUninitialize()

객체생성

도움말을 열어봤을때 좌측에 보이는 주요 네가지 라이브러리인

  • CpDib : 혹은 DSCBO1
  • CpSysDib
  • CpTrade
  • CpUtil

각각에 속하는 coclass들을 "."으로 연결하여 객체를 생성할수 있습니다. Create 메서드로 COM객체 생성을 Release 메서드로 헤제를 할수 있습니다.

	stkmst := &cpgo.CpClass{}
	stkmst.Create("CpDib.StockMst")
	defer stkmst.Release()

주요 인터페이스

기본적인 동작을 위해 구현된 주요 인터페이스 메서드들입니다.

  • SetInputValue : 입력데이터 세팅
  • Request : Non-blocking 요청
  • BlockRequest : Blocking 요청
  • Subscribe : 실시간 수신 요청
  • SubscribeLastest : 실시간 수신 (스냅샷성 데이터) 요청
  • Unsubscribe : 실시간 수신 해지
  • GetHeaderValue : 수신 헤더데이터
  • GetDataValue : 수신 데이터
	stkmst.SetInputValue(0, "A000270")
	stkmst.BlockRequest()
	fmt.Println(stkmst.GetHeaderValue(1).Value())

Property

Property값을 가져오려면 getter를 사용하여야 합니다. 도움말의 Property명에 앞에 Get을 붙인 메서드명을 사용합니다.

	tmp := &CpClass{}
	tmp.Create("CpUtil.CpCybos")
	defer tmp.Release()
	fmt.Println(tmp)

	fmt.Println("isconnect: ", tmp.GetIsConnect().Value())
	fmt.Println("servertype: ", tmp.GetServerType().Value())
	fmt.Println("remain time: ", tmp.GetLimitRequestRemainTime().Value())

이벤트처리

Received 이벤트는 Receiver 인터페이스를 구현하면 됩니다.

type Receiver interface {
	Received(*CpClass)
}

이를 BindEvent 메서드를 사용하여 이벤트를 지정할수 있습니다. 이벤트를 해지하려면 UnbindEvent 메서드를 사용합니다.

type RqTestStruct struct {
}

func (t *RqTestStruct) Received(c *CpClass) {
	fmt.Println(c.GetHeaderValue(1).Value())
	c.UnbindEvent() // 이벤트 바로 헤제
}
//... 생략

	evnt := &RqTestStruct{}
	cpobj.BindEvent(evnt)

PeekMessage 를 기반으로 동작하는 PumpWaitingMessages 함수를 제공합니다. 이를 사용하여 Received이벤트를 수신할때까지 대기할수 있습니다.

for  {
	PumpWaitingMessages()
	time.Sleep(1)
}

예제

통신방식을 기준으로 작성한 몇가지 예제입니다.

BlockRequest사용

package main

import (
	"fmt"

	ole "github.com/go-ole/go-ole"
	"github.com/ippoeyeslhw/cpgo"
)

func main() {
	ole.CoInitialize(0)
	defer ole.CoUninitialize()

	stkmst := &cpgo.CpClass{}
	stkmst.Create("CpDib.StockMst")
	defer stkmst.Release()

	stkmst.SetInputValue(0, "A000270")
	stkmst.BlockRequest()
	fmt.Println(stkmst.GetHeaderValue(1).Value())
}
// 결과:
// 기아차

Request사용

package main

import (
	"fmt"
	"time"

	ole "github.com/go-ole/go-ole"
	"github.com/ippoeyeslhw/cpgo"
)

type ContEvnt struct {
	isDone bool
}

func (s *ContEvnt) Received(c *cpgo.CpClass) {
	count := c.GetHeaderValue(2).Value().(int16) // 수신개수
	fmt.Println("response count: ", count)
	for i := 0; i < int(count); i++ {
		fmt.Println(
			c.GetDataValue(1, i).Value(), // 종목코드
			c.GetDataValue(4, i).Value()) // 내용
	}
	if c.GetContinue().Value() == int32(1) { // 연속데이터 있음
		fmt.Println("next request")
		c.Request() // 재요청
	} else {
		s.isDone = true
	}
}

func main() {
	ole.CoInitialize(0)
	defer ole.CoUninitialize()

	cpmw := &cpgo.CpClass{}
	cpmw.Create("CpSysDib.CpMarketWatch")
	defer cpmw.Release()

	evnt := &ContEvnt{false}
	cpmw.BindEvent(evnt)

	// 연속조회  request 갯수제한 유의
	cpmw.SetInputValue(0, "*") // 전종목
	cpmw.SetInputValue(1, "2") // 공시정보
	cpmw.Request()

	for evnt.isDone == false {
		cpgo.PumpWaitingMessages()
		time.Sleep(1)
	}
	cpmw.UnbindEvent()
}

// 결과:
//response count:  20
//A151910 나노스(주) 주권매매거래정지기간변경(개선기간 부여)
//A043290 케이맥(주) 단일판매ㆍ공급계약체결
//A151910 나노스(주) 기타시장안내(기업심사위원회 심의결과 및 개선기간 부여 안내)
//A900050 중국원양자원유한공사 기타 경영사항(자율공시)(자회사의 주요경영사항)
//A043710 (주)서울리거 기타시장안내(상장적격성 실질심사사유 추가 관련 )
//A065420 (주)에스아이리소스 주권매매거래정지(불성실공시법인 지정)
//A065420 (주)에스아이리소스 불성실공시법인지정(공시불이행)
//A011200 현대상선(주) 전환가액ㆍ신주인수권행사가액ㆍ교환가액의 조정(안내공시)
//A011200 현대상선(주) 전환가액ㆍ신주인수권행사가액ㆍ교환가액의 조정(안내공시)
// ...
// ...

Subscribe 예제

package main

import (
	"fmt"
	"time"

	ole "github.com/go-ole/go-ole"
	"github.com/ippoeyeslhw/cpgo"
)

type SubTestStruct struct {
	cont bool
	cnt  int
}

func (s *SubTestStruct) Received(c *cpgo.CpClass) {

	fmt.Printf("(%f)%d , (%f)%d\n",
		c.GetHeaderValue(14).Value(), // 1차 매수호가
		c.GetHeaderValue(15).Value(), // 1차 매수잔량
		c.GetHeaderValue(25).Value(), // 1차 매도호가
		c.GetHeaderValue(26).Value()) // 1차 매도잔량

	if s.cnt > 100 {
		// 100건이 넘을시 중단
		s.cont = false
	}
	s.cnt++
}

func main() {
	ole.CoInitialize(0)
	defer ole.CoUninitialize()

	tmp := &cpgo.CpClass{}
	tmp.Create("CpSysDib.CmeCurr")
	defer tmp.Release()
	fmt.Println(tmp)

	evnt := &SubTestStruct{true, 0}
	tmp.BindEvent(evnt)
	fmt.Println(tmp)

	// 야간 CME 선물시장 밤에 테스트할것
	tmp.SetInputValue(0, "101L9")
	tmp.Subscribe()

	fmt.Println("sub/pub start")

	for evnt.cont == true {
		cpgo.PumpWaitingMessages()
		time.Sleep(1)
	}
	tmp.Unsubscribe()
	tmp.UnbindEvent()
}

// 결과:
//sub/pub start
//(251.449997)30 , (251.500000)2
//(251.449997)35 , (251.500000)2
//(251.449997)35 , (251.550003)34
//(251.449997)35 , (251.550003)34
//(251.449997)35 , (251.550003)34
//(251.449997)35 , (251.500000)1
// ...
// ...

이벤트수신문제

Subscribe 통신방식으로 이벤트 수신을 지속적으로 받다보면 이벤트 수신이 중간에 끊어졌다가 다시 연결되었다가 하는 현상이 발견됩니다. COM 객체는 이벤트 싱크를 맺은 윈도우 스레드에만 메세지를 전달합니다. Go언어의 스케줄러는 다수의 OS Thread 와 다수의 Goroutine 을 가지고 스케줄링 하여 윈도우 스레드가 중간에 바뀌어 끊어지는 것입니다. 이를 방지하기 위해 윈도우 스레드 함수 Wrapper를 사용할수 있습니다.

type Background func(uintptr) uintptr

uintptr 을 인자로 받고 uintptr을 리턴하는 함수를 선언합니다.

func CreateThread(fnc Background, arg1 uintptr) (ret int32, err error)

함수와 인자로 넘겨줄 값을 넘겨주어 스레드를 생성합니다.

type CmeCurEvnt struct {
}

func (ce *CmeCurEvnt) Received(c *cpgo.CpClass) {
	fmt.Printf("[%v] (%f)%d , (%f)%d\n",
		time.Now(),
		c.GetHeaderValue(14).Value(), // 1차 매수호가
		c.GetHeaderValue(15).Value(), // 1차 매수잔량
		c.GetHeaderValue(25).Value(), // 1차 매도호가
		c.GetHeaderValue(26).Value()) // 1차 매도잔량
}

func loop(p uintptr) uintptr {
	// 윈도우 스레드에서 돌아갈 코드
	ole.CoInitialize(0)
	defer ole.CoUninitialize()

	// create cp class
	tmp := &cpgo.CpClass{}
	tmp.Create("CpSysDib.CmeCurr")
	defer tmp.Release()

	// event binding
	evnt := &CmeCurEvnt{}
	tmp.BindEvent(evnt)
	defer tmp.UnbindEvent()

	// set input values
	tmp.SetInputValue(0, "101M3")
	tmp.Subscribe()
	defer tmp.Unsubscribe()

	for {
		cpgo.PumpWaitingMessages()
		time.Sleep(1)
	}

	return 0
}

func main() {

	// 스레드 생성
	cpgo.CreateThread(loop, 0)

	// 메인스레드 Waiting
	for { 
		time.Sleep(time.Millisecond * 10)
	}
}

cpgo's People

Contributors

ippoeyeslhw avatar

Stargazers

aero avatar paxbug avatar Cellularhacker avatar P.Elley avatar creativeshim avatar Ben Park avatar sangx2 avatar  avatar  avatar

Watchers

 avatar MinUk Hwang avatar creativeshim avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.