func (client *Client) runBookLoop(bookChan chan<- exchange.Book) {
	for resp := range client.readBookMsg {
		bookChan <- client.convertToBook(resp)
	}
}
Book WebSocket read loop
package okcoin
import (
	"bitfx/exchange"
	"crypto/md5"
	"encoding/json"
	"fmt"
	"log"
	"math"
	"net/http"
	"net/url"
	"sort"
	"strings"
	"time"
	"github.com/gorilla/websocket"
)
type Client struct {
	key, secret, symbol, currency, websocketURL, name string
	priority                                          int
	position, fee, maxPos, availShort, availFunds     float64
	currencyCode                                      byte
	done                                              chan bool
	writeBookMsg                                      chan request
	readBookMsg                                       chan response
	writeOrderMsg                                     chan request
	readOrderMsg                                      chan response
}
type request struct {
	Event      string            `json:"event"`       
	Channel    string            `json:"channel"`     
	Parameters map[string]string `json:"parameters"`  
}
type response []struct {
	Channel   string          `json:"channel"`           
	ErrorCode int64           `json:"errorcode,string"`  
	Data      json.RawMessage `json:"data"`              
}
func New(key, secret, symbol, currency string, priority int, fee, availShort, availFunds float64) *Client {
	var websocketURL string
	var currencyCode byte
	if strings.ToLower(currency) == "usd" {
		websocketURL = "wss://real.okcoin.com:10440/websocket/okcoinapi"
		currencyCode = 0
	} else if strings.ToLower(currency) == "cny" {
		websocketURL = "wss://real.okcoin.cn:10440/websocket/okcoinapi"
		currencyCode = 1
	} else {
		log.Fatal("Currency must be USD or CNY")
	}
	name := fmt.Sprintf("OKCoin(%s)", currency)
	done := make(chan bool, 2)
	writeBookMsg := make(chan request)
	readBookMsg := make(chan response)
	writeOrderMsg := make(chan request)
	readOrderMsg := make(chan response)
	client := &Client{
		key:           key,
		secret:        secret,
		symbol:        symbol,
		currency:      currency,
		websocketURL:  websocketURL,
		priority:      priority,
		fee:           fee,
		availShort:    availShort,
		availFunds:    availFunds,
		currencyCode:  currencyCode,
		name:          name,
		done:          done,
		writeOrderMsg: writeOrderMsg,
		readOrderMsg:  readOrderMsg,
		writeBookMsg:  writeBookMsg,
		readBookMsg:   readBookMsg,
	}
	initMsg := request{Event: "addChannel", Channel: fmt.Sprintf("ok_%s%s_depth", symbol, currency)}
	go client.maintainWS(initMsg, writeBookMsg, readBookMsg)
	go client.maintainWS(request{}, writeOrderMsg, readOrderMsg)
	return client
}
func (client *Client) Done() {
	client.done <- true
	client.done <- true
	close(client.readBookMsg)
	close(client.readOrderMsg)
}
func (client *Client) String() string {
	return client.name
}
func (client *Client) Priority() int {
	return client.priority
}
func (client *Client) Fee() float64 {
	return client.fee
}
func (client *Client) SetPosition(pos float64) {
	client.position = pos
}
func (client *Client) Position() float64 {
	return client.position
}
func (client *Client) Currency() string {
	return client.currency
}
func (client *Client) CurrencyCode() byte {
	return client.currencyCode
}
func (client *Client) SetMaxPos(maxPos float64) {
	client.maxPos = maxPos
}
func (client *Client) MaxPos() float64 {
	return client.maxPos
}
func (client *Client) AvailFunds() float64 {
	return client.availFunds
}
func (client *Client) AvailShort() float64 {
	return client.availShort
}
func (client *Client) HasCryptoFee() bool {
	return true
}
func (client *Client) CommunicateBook(bookChan chan<- exchange.Book) exchange.Book {
	book := client.convertToBook(<-client.readBookMsg)
	go client.runBookLoop(bookChan)
	return book
}