语言环境为>=go1.10
go语言环境不多说
实现目的能与BitMEX api进行交互自动交易,目前虚拟币平台很多,平台API实现也很容易.后续会加上其它平台和自动交易算法策略,具体看平台交易手续费性价比而定.
先从国内平台开始,以GO语言为例子,其他语言也有很多,主要是学习GO语言.
这里需要用到websocket,当然还有其他形式的请求API,这里以这种形式为例子,
先从火币开始,如果不知道API具体参数可查看官网.
先在我的GOPATH中的SRC目录中创建一个文件夹,为huobi,在这个文件夹中创建一个主程序main.go,单纯请求火币获取行情参数.
websocket使用第三方包使用,github.com/gorilla/websocket,比官方的net包多些功能.引入后创建类型拨号器,然后拨号
这是拨号器结构体,拨号器包含连接websocket的选项
type Dialer struct { // NetDial specifies the dial function for creating TCP connections. If // NetDial is nil, net.Dial is used. NetDial func(network, addr string) (net.Conn, error) // Proxy specifies a function to return a proxy for a given // Request. If the function returns a non-nil error, the // request is aborted with the provided error. // If Proxy is nil or returns a nil *URL, no proxy is used. Proxy func(*http.Request) (*url.URL, error) // TLSClientConfig specifies the TLS configuration to use with tls.Client. // If nil, the default configuration is used. TLSClientConfig *tls.Config // HandshakeTimeout specifies the duration for the handshake to complete. HandshakeTimeout time.Duration // ReadBufferSize and WriteBufferSize specify I/O buffer sizes. If a buffer // size is zero, then a useful default size is used. The I/O buffer sizes // do not limit the size of the messages that can be sent or received. ReadBufferSize, WriteBufferSize int // Subprotocols specifies the client\'s requested subprotocols. Subprotocols []string // EnableCompression specifies if the client should attempt to negotiate // per message compression (RFC 7692). Setting this value to true does not // guarantee that compression will be supported. Currently only "no context // takeover" modes are supported. EnableCompression bool // Jar specifies the cookie jar. // If Jar is nil, cookies are not sent in requests and ignored // in responses. Jar http.CookieJar }
根据需求创建好后拨号,包含字符串很请求协议,协议一般为nil
func (d *Dialer) Dial(urlStr string, requestHeader http.Header) (*Conn, *http.Response, error)
接下来进入API规则部分,对应火币,
完整代码
package main import ( "fmt" "time" "strconv" //字符串转换 "encoding/json" //JSON包 "github.com/gorilla/websocket" //go的websocket实现 "huobi/common" "huobi/conf" ) func main() { dialer := websocket.Dialer{/*根据需要设置字段*/} //类型拨号器 ws, _, err := dialer.Dial("wss://api.huobi.pro/ws", nil) //拨号,返回连接对象,响应和错误 if err != nil { // handle error } for { //因为是websocket,所以是不停的 if _,p,err := ws.ReadMessage();err == nil { //读取信息,这里是火币的规则 res := common.UnGzip(p) //解压数据 fmt.Println(string(res)) //输出字符串 resMap := common.JsonDecodeByte(res) //JSON解码 if v, ok := resMap["ping"];ok { pingMap := make(map[string]interface{}) pingMap["pong"] = v //发送pong包,完成ping,pong pingParams := common.JsonEncodeMapToByte(pingMap) //转成JSON if err := ws.WriteMessage(websocket.TextMessage, pingParams); err == nil { //发送消息,TextMessage是整型,整数常量来标识两种数据消息类型 reqMap := new(common.ReqStruct)//创建结构体指针 reqMap.Id = strconv.Itoa(time.Now().Nanosecond()) reqMap.Req = conf.LtcTopic.KLineTopicDesc reqBytes , err := json.Marshal(reqMap) if err!=nil { continue } if err := ws.WriteMessage(websocket.TextMessage,reqBytes); err == nil { //发送ID REQ }else{ fmt.Errorf("send req response error %s",err.Error()) } }else{ fmt.Errorf("huobi server ping client error %s",err.Error()) continue } } if _, ok := resMap["rep"];ok { var resStruct common.ResStruct json.Unmarshal(res,&resStruct) //resStruct.Status fmt.Println(resStruct)//输出内容 } } } }
如果无法访问还需设置代理
dialer := websocket.Dialer{Proxy:func(*http.Request) (*url.URL, error) { return url.Parse("http://127.0.0.1:1080") }, //类型拨号器 }
流程:
1.火币的API数据都是gzip压缩过的,所以一开始连接API接收数据需要把数据进行解压
2.解压完输出内容,输出完进行JSON的解析,然后把PING对应的值取出赋值给PING发送回去,这是火币心跳包检测,两次没发回去则断开连接
3.然后请求需要获取的币种格式,market.$symbol.kline.$period对应
"req": "market.btcusdt.kline.1min",
"id": "id10"
4.这是请求数据,然后会得到反馈