├── README.md └── huobi ├── const.go ├── huobi_test.go ├── market.go └── trading.go /README.md: -------------------------------------------------------------------------------- 1 | # coin 数字货币交易平台API 2 | digiccy trading platform API collection, such as Bitcoin, Litecoin. current complete huobi api v3. 3 | 4 | 数字货币交易平台API,目前包含了火币网的API V3的大部分接口,包含交易和行情接口,剩余的接口会陆续完善。其他平台的API接口后续补充。 5 | ##火币网API V3 6 | 7 | ## 安装 8 | ```go 9 | go get -u github.com/lemtree/coin 10 | ``` 11 | 12 | 13 | ## 实例 14 | #### 实例一:获取当前市场行情 15 | ```go 16 | package main 17 | 18 | import ( 19 | "fmt" 20 | "github.com/lemtree/coin/huobi" 21 | ) 22 | 23 | func main() { 24 | c := huobi.NewHuobiClient() 25 | 26 | //获取BTC-CNY行情,返回解析好的struct 27 | QuoData, err := c.Quotation(huobi.COIN_BTC, huobi.CURRENCY_CNY) 28 | checkError(err) 29 | fmt.Printf("当前BTC-CNY报价(golang struct):%+v \r\n", QuoData) 30 | 31 | //获取BTC-CNY行情,返回火币api的原始JSON 32 | jsonBlob, err := c.QuotationJson(huobi.COIN_BTC, huobi.CURRENCY_CNY) 33 | checkError(err) 34 | fmt.Print("当前BTC-CNY报价(火币API原始json):", string(jsonBlob)) 35 | 36 | } 37 | 38 | func checkError(err error) { 39 | if err != nil { 40 | fmt.Println(err.Error()) 41 | } 42 | } 43 | 44 | ``` 45 | 对应火币API接口,我们可以获取火币api原始json信息或者解析后的struct结构信息,调用其中一种即可。 46 | 47 | #### 实例二:获取我的账户信息 48 | ```go 49 | package main 50 | 51 | import ( 52 | "fmt" 53 | "github.com/lemtree/coin/huobi" 54 | ) 55 | 56 | func main() { 57 | c := huobi.NewHuobiClient() 58 | 59 | // 获取我的账户信息,需要在火币网获取访问秘钥,然后设置你的API key 60 | c.SetApiKey("your-access-key", "your-secret-key") 61 | 62 | accountInfo, err := c.GetAccountInfo() 63 | if err != nil { 64 | fmt.Println(err.Error()) 65 | } else { 66 | fmt.Printf("我的资产:%+v", accountInfo) 67 | } 68 | } 69 | ``` 70 | #### 注意:个人账户、买卖下单等操作的默认交易市场是人民币市场。若要操作美元市场,设置 c.SetMarket("usd") 即可。 71 | 72 | 73 | ## API接口其他补充说明 74 | 本接口尽量保持和火币的API接口一致
75 | 每个对应火币网的API接口函数都有2种,一种是直接返回火币api的原始json,另一种是解析后的struct,更方便操作。详细请看实例一。
76 | 例如获取实时行情: func Quotation() 返回的是解析后的struct, func QuotationJson()返回的是huobi api的原始json。其他接口也类似。
77 | 基于火币的API返回的原始Json,对于数字和字符串没有严格的区分,有的接口返回的json中价格是字符串,有的接口中是浮点型。如果客户端是弱类型语言则不需额外处理,但是强类型语言则可能直接导致异常。如果你想保持和火币网一致,可以使用 funcname+Json的函数返回api的原始json,如果想规范点,则使用返回struct的接口,然后把返回的struct format成json,这样输出的json数字和字符串就统一了,不会出现价格可能是字符串也可能是浮点型的问题了。 78 | 79 | 80 | ## 更多 81 | 利用放年假的前几天的空暇时间完成,虽然已经对API借口做了测试,但是仍难免有疏漏之处,如果发现bug,请联系QQ:290924805。
82 | 也欢迎讨论各种交易策略。 83 | -------------------------------------------------------------------------------- /huobi/const.go: -------------------------------------------------------------------------------- 1 | package huobi 2 | 3 | const ( 4 | HOST = "https://api.huobi.com/" 5 | API_V3_URI = HOST + "apiv3/" 6 | ) 7 | 8 | type PeriodT int 9 | type CoinT int 10 | type CurrencyT int 11 | 12 | // K线周期 13 | const ( 14 | PERIOD_1_MINS PeriodT = 1 15 | PERIOD_5_MINS = 5 16 | PERIOD_15_MINS = 15 17 | PERIOD_30_MINS = 30 18 | PERIOD_60_MINS = 60 19 | PERIOD_1_DAY = 100 20 | PERIOD_1_WEEK = 200 21 | PERIOD_1_MONTH = 300 22 | PERIOD_1_YEAR = 400 23 | ) 24 | 25 | // 数字货币 26 | const ( 27 | COIN_BTC CoinT = 1 + iota 28 | COIN_LTC 29 | ) 30 | 31 | //法币 32 | const ( 33 | CURRENCY_CNY CurrencyT = 1 + iota 34 | CURRENCY_USD 35 | ) 36 | 37 | // 根据coin获得coin name,获取url时用 38 | var coinNames map[CoinT]string = map[CoinT]string{COIN_BTC: "btc", COIN_LTC: "ltc"} 39 | 40 | // 根据currency获得currency name,获取url时用 41 | var marketNames map[CurrencyT]string = map[CurrencyT]string{CURRENCY_CNY: "staticmarket", CURRENCY_USD: "usdmarket"} 42 | 43 | // 账号下的资产信息 44 | type AccountInfo struct { 45 | Total float64 `json:"total,string"` 46 | NetAsset float64 `json:"net_asset,string"` 47 | AvailableCnyDisplay float64 `json:"available_cny_display,string"` 48 | AvailableBtcDisplay float64 `json:"available_btc_display,string"` 49 | AvailableLtcDisplay float64 `json:"available_ltc_display,string"` 50 | FrozenCnyDisplay float64 `json:"frozen_cny_display,string"` 51 | FrozenBtcDisplay float64 `json:"frozen_btc_display,string"` 52 | FrozenLtcDisplay float64 `json:"frozen_ltc_display,string"` 53 | LoanCnyDisplay float64 `json:"loan_cny_display,string"` 54 | LoanBtcDisplay float64 `json:"loan_btc_display,string"` 55 | LoanLtcDisplay float64 `json:"loan_ltc_display,string"` 56 | } 57 | 58 | // 批量返回的订单的单条信息 59 | type Order struct { 60 | Id int `json:"id"` 61 | Type int `json:type` 62 | OrderPrice float64 `json:"order_price,string"` 63 | OrderAmount float64 `json:"order_amount,string"` 64 | ProcessedAmount float64 `json:"processed_amount,string"` 65 | OrderTime int `json:"order_time"` 66 | } 67 | 68 | // 返回某一条订单的详细信息 69 | type OrderInfo struct { 70 | Id int `json:"id"` 71 | Type int `json:type` 72 | OrderPrice float64 `json:"order_price,string"` 73 | OrderAmount float64 `json:"order_amount,string"` 74 | ProcessedPrice float64 `json:"processed_price,string"` 75 | ProcessedAmount float64 `json:"processed_amount,string"` 76 | Vot float64 `json:"vot,string"` 77 | Fee float64 `json:"fee,string"` 78 | Total float64 `json:"total,string"` 79 | Status int `json:"status"` 80 | } 81 | 82 | // 已经成交的订单的信息 83 | type OrderTraded struct { 84 | Order 85 | LastProcessedTime int `json:"last_processed_time"` 86 | Status int `json:"status"` 87 | } 88 | 89 | // 通用返回信息 90 | type Result struct { 91 | Result string `json:"result"` 92 | Id int `json:"id"` 93 | } 94 | 95 | // k线图 96 | type Kline struct { 97 | DateTime int 98 | Open float64 99 | High float64 100 | Low float64 101 | Close float64 102 | Volue float64 103 | } 104 | 105 | // 返回的实时行情 106 | type RealTimeQuotation struct { 107 | DateTime int `json:"time,string"` 108 | Ticker RealTimeQuotationTicker 109 | } 110 | 111 | // 返回的实时行情 ticker 112 | type RealTimeQuotationTicker struct { 113 | High float64 114 | Low float64 115 | Symbol string 116 | Last float64 117 | Volue float64 `json:"vol"` 118 | Buy float64 119 | Sell float64 120 | Open float64 121 | } 122 | 123 | type Depth struct { 124 | Asks [][]float64 125 | Bids [][]float64 126 | Symbol string 127 | } 128 | 129 | // 实时行情 130 | type RealTimeTransactionData struct { 131 | Amount float64 132 | Level float64 133 | Buys []RealTimeTransactionDataSubBuy 134 | Phigh float64 `json:"p_high"` 135 | Plast float64 `json:"p_last"` 136 | Plow float64 `json:"p_low"` 137 | Pnew float64 `json:"p_new"` 138 | Popen float64 `json:"p_open"` 139 | Sells []RealTimeTransactionDataSubBuy 140 | TopBuy []RealTimeTransactionDataSubTopBuy `json:"top_buy"` 141 | TopSell []RealTimeTransactionDataSubTopBuy `json:"top_sell"` 142 | Total float64 143 | Trades []RealTimeTransactionDataSubTrade 144 | Symbol string 145 | } 146 | 147 | //实时行情下的trade结构 148 | type RealTimeTransactionDataSubTrade struct { 149 | Amount float64 150 | Price float64 151 | Time string 152 | EnType string `json:"en_type"` 153 | Type string 154 | } 155 | 156 | //实时行情下的buy或sell结构 157 | type RealTimeTransactionDataSubBuy struct { 158 | Amount float64 159 | Level int 160 | Price float64 161 | } 162 | 163 | //实时行情下的top_buy或top_sell结构 164 | type RealTimeTransactionDataSubTopBuy struct { 165 | RealTimeTransactionDataSubBuy 166 | Accu float64 167 | } 168 | -------------------------------------------------------------------------------- /huobi/huobi_test.go: -------------------------------------------------------------------------------- 1 | package huobi 2 | 3 | import ( 4 | "test" 5 | ) 6 | -------------------------------------------------------------------------------- /huobi/market.go: -------------------------------------------------------------------------------- 1 | /** 2 | * 火币 www.huobi.com API 行情接口 3 | * Auth HuHeKun 4 | * Date 2017-01-17 5 | */ 6 | package huobi 7 | 8 | import ( 9 | "encoding/json" 10 | "fmt" 11 | "net/url" 12 | "strconv" 13 | ) 14 | 15 | var KlineUrl = HOST + "%s" + "/" + "%s" + "_kline_" + "%03d" + "_json.js" 16 | var QuotationUrl = HOST + "%s" + "/" + "ticker_%s_json.js" 17 | var DepthUrl = HOST + "%s/depth_%s_%d.js" 18 | var RealTimeTransactionUrl = HOST + "%s/detail_%s_json.js" 19 | 20 | /** 21 | * 获取K线图 22 | * coinType 数字货币 BTC\LTC 23 | * currency 法币类型 CNY\USD 24 | * period 周期 25 | * length 数据条数 26 | */ 27 | func (hb *HuobiClient) Kline(coinType CoinT, currencyType CurrencyT, period PeriodT, length int) ([]Kline, error) { 28 | klines := []Kline{} 29 | dataMap := [][]interface{}{} 30 | jsonBlob, err := hb.KlineJson(coinType, currencyType, period, length) 31 | if err != nil { 32 | return klines, err 33 | } 34 | err = json.Unmarshal(jsonBlob, &dataMap) 35 | if err != nil { 36 | return klines, err 37 | } 38 | 39 | for _, row := range dataMap { 40 | kline := Kline{} 41 | kline.DateTime, _ = strconv.Atoi(row[0].(string)) 42 | kline.Open = row[1].(float64) 43 | kline.High = row[2].(float64) 44 | kline.Low = row[3].(float64) 45 | kline.Close = row[4].(float64) 46 | kline.Volue = row[5].(float64) 47 | klines = append(klines, kline) 48 | } 49 | 50 | return klines, nil 51 | } 52 | 53 | /** 54 | * 获取K线图 55 | * coinType 数字货币 BTC\LTC 56 | * currency 法币类型 CNY\USD 57 | * period 周期 58 | * length 数据条数 59 | */ 60 | func (hb *HuobiClient) KlineJson(coinType CoinT, currencyType CurrencyT, period PeriodT, length int) ([]byte, error) { 61 | uri := hb.generateKlineApiUrl(coinType, currencyType, period) 62 | v := url.Values{} 63 | v.Set("length", strconv.Itoa(length)) 64 | parameter := v.Encode() 65 | return hb.SendRequest(uri, parameter) 66 | } 67 | 68 | // 根据cointype返回coin的小写名称 btc/ltc 69 | func (hb *HuobiClient) getCoinName(coinType CoinT) string { 70 | if coinName, ok := coinNames[coinType]; ok { 71 | return coinName 72 | } 73 | return "" 74 | } 75 | 76 | // 根据currency返回market cny:staticmarket usd:usdmarket 77 | func (hb *HuobiClient) getMarketName(currencyType CurrencyT) string { 78 | if marketName, ok := marketNames[currencyType]; ok { 79 | return marketName 80 | } 81 | return "" 82 | } 83 | 84 | func (hb *HuobiClient) generateKlineApiUrl(coinType CoinT, currencyType CurrencyT, period PeriodT) string { 85 | coinName := hb.getCoinName(coinType) 86 | marketName := hb.getMarketName(currencyType) 87 | return fmt.Sprintf(KlineUrl, marketName, coinName, period) 88 | } 89 | 90 | /** 91 | * BTC-CNY K线图 92 | */ 93 | func (hb *HuobiClient) KlineBtcCny(period PeriodT, length int) ([]Kline, error) { 94 | return hb.Kline(COIN_BTC, CURRENCY_CNY, period, length) 95 | } 96 | 97 | /** 98 | * BTC-USD K线图 99 | */ 100 | func (hb *HuobiClient) KlineBtcUsd(period PeriodT, length int) ([]Kline, error) { 101 | return hb.Kline(COIN_BTC, CURRENCY_USD, period, length) 102 | } 103 | 104 | /** 105 | * LTC-USD K线图 106 | */ 107 | func (hb *HuobiClient) KlineLtcCny(period PeriodT, length int) ([]Kline, error) { 108 | return hb.Kline(COIN_LTC, CURRENCY_CNY, period, length) 109 | } 110 | 111 | /** 112 | * 实时行情 113 | * coinType 数字货币 BTC\LTC 114 | * currency 法币类型 CNY\USD 115 | */ 116 | func (hb *HuobiClient) Quotation(coinType CoinT, currencyType CurrencyT) (*RealTimeQuotation, error) { 117 | realTimeQuotation := &RealTimeQuotation{} 118 | jsonBlob, err := hb.QuotationJson(coinType, currencyType) 119 | if err != nil { 120 | return realTimeQuotation, err 121 | } 122 | err = json.Unmarshal(jsonBlob, realTimeQuotation) 123 | if err != nil { 124 | return realTimeQuotation, err 125 | } 126 | return realTimeQuotation, nil 127 | } 128 | 129 | /** 130 | * 实时行情(返回API的json字符串) 131 | * coinType 数字货币 BTC\LTC 132 | * currency 法币类型 CNY\USD 133 | */ 134 | func (hb *HuobiClient) QuotationJson(coinType CoinT, currencyType CurrencyT) ([]byte, error) { 135 | coinName := hb.getCoinName(coinType) 136 | marketName := hb.getMarketName(currencyType) 137 | uri := fmt.Sprintf(QuotationUrl, marketName, coinName) 138 | return hb.SendRequest(uri, "") 139 | } 140 | 141 | /** 142 | * 交易深度 143 | * coinType 数字货币 BTC\LTC 144 | * currency 法币类型 CNY\USD 145 | * length 返回的数据条数 146 | */ 147 | func (hb *HuobiClient) Depth(coinType CoinT, currencyType CurrencyT, length int) (*Depth, error) { 148 | depths := &Depth{} 149 | jsonBlob, err := hb.DepthJson(coinType, currencyType, length) 150 | if err != nil { 151 | return depths, err 152 | } 153 | err = json.Unmarshal(jsonBlob, depths) 154 | if err != nil { 155 | return depths, err 156 | } 157 | return depths, nil 158 | } 159 | 160 | /** 161 | * 交易深度(返回API的json字符串) 162 | * coinType 数字货币 BTC\LTC 163 | * currency 法币类型 CNY\USD 164 | * length 返回的数据条数 165 | */ 166 | func (hb *HuobiClient) DepthJson(coinType CoinT, currencyType CurrencyT, length int) ([]byte, error) { 167 | coinName := hb.getCoinName(coinType) 168 | marketName := hb.getMarketName(currencyType) 169 | uri := fmt.Sprintf(DepthUrl, marketName, coinName, length) 170 | return hb.SendRequest(uri, "") 171 | } 172 | 173 | /** 174 | * 买卖盘实时成交数据 175 | * coinType 数字货币 BTC\LTC 176 | * currency 法币类型 CNY\USD 177 | */ 178 | func (hb *HuobiClient) RealTimeTransaction(coinType CoinT, currencyType CurrencyT) (*RealTimeTransactionData, error) { 179 | transactionData := &RealTimeTransactionData{} 180 | jsonBlob, err := hb.RealTimeTransactionJson(coinType, currencyType) 181 | if err != nil { 182 | return transactionData, err 183 | } 184 | err = json.Unmarshal(jsonBlob, transactionData) 185 | if err != nil { 186 | return transactionData, err 187 | } 188 | return transactionData, nil 189 | } 190 | 191 | /** 192 | * 买卖盘实时成交数据 193 | * coinType 数字货币 BTC\LTC 194 | * currency 法币类型 CNY\USD 195 | */ 196 | func (hb *HuobiClient) RealTimeTransactionJson(coinType CoinT, currencyType CurrencyT) ([]byte, error) { 197 | coinName := hb.getCoinName(coinType) 198 | marketName := hb.getMarketName(currencyType) 199 | uri := fmt.Sprintf(RealTimeTransactionUrl, marketName, coinName) 200 | return hb.SendRequest(uri, "") 201 | } 202 | -------------------------------------------------------------------------------- /huobi/trading.go: -------------------------------------------------------------------------------- 1 | /** 2 | * 火币 www.huobi.com API 交易接口 3 | * Auth HuHeKun 4 | * Date 2017-01-17 5 | * 目前 trade_password trade_id 还未实现,以及BTC\LTC提现等暂时未用到,如有需求后续完成 6 | */ 7 | package huobi 8 | 9 | import ( 10 | "encoding/json" 11 | "errors" 12 | "fmt" 13 | "io/ioutil" 14 | 15 | "net/http" 16 | "net/url" 17 | "strconv" 18 | "strings" 19 | "time" 20 | 21 | "github.com/lemtree/funcs" 22 | ) 23 | 24 | var huobiDebug bool 25 | 26 | type HuobiClient struct { 27 | httpClient *http.Client 28 | accessKey string 29 | secretKey string 30 | market string 31 | // trade_password 32 | userAgent string 33 | } 34 | 35 | // huobi client 36 | func NewHuobiClient() *HuobiClient { 37 | client := &http.Client{} 38 | return &HuobiClient{httpClient: client, accessKey: "", secretKey: "", market: "cny", userAgent: "HHK Client"} 39 | } 40 | 41 | /** 42 | * 设置api访问秘钥 43 | * accessKey huobi api AccessKey 44 | * secretKey huobi api SecretKey 45 | */ 46 | func (hb *HuobiClient) SetApiKey(accessKey, secretKey string) { 47 | hb.accessKey = accessKey 48 | hb.secretKey = secretKey 49 | } 50 | 51 | /** 52 | * 设置http header的User-Agent 53 | * userAgent User-Agent信息 54 | */ 55 | func (hb *HuobiClient) SetUserAgent(userAgent string) { 56 | hb.userAgent = userAgent 57 | } 58 | 59 | /** 60 | * 设置交易市场,人民币市场还是美元市场 61 | * market 交易市场(cny:人民币交易市场,usd:美元交易市场) 62 | */ 63 | func (hb *HuobiClient) SetMarket(market string) { 64 | hb.market = market 65 | } 66 | 67 | /** 68 | * 生成请求的参数 69 | */ 70 | func (hb *HuobiClient) generateParameter(parameter map[string]string) string { 71 | v := url.Values{} 72 | for key, val := range parameter { 73 | v.Set(key, val) 74 | } 75 | v.Set("access_key", hb.accessKey) 76 | v.Set("created", strconv.Itoa(int(time.Now().Unix()))) 77 | v.Set("secret_key", hb.secretKey) 78 | v.Set("sign", tools.MD5([]byte(v.Encode()))) 79 | v.Del("secret_key") 80 | v.Set("market", hb.market) 81 | return v.Encode() 82 | } 83 | 84 | /** 85 | * 获取个人账户信息 86 | */ 87 | func (hb *HuobiClient) GetAccountInfo() (*AccountInfo, error) { 88 | account := &AccountInfo{} 89 | jsonBlob, err := hb.GetAccountInfoJson() 90 | //jsonBlob = []byte(`{"total":"2163.32","net_asset":"2163.32","available_cny_display":"2163.32","available_btc_display":"1.23000","available_ltc_display":"2.2300","frozen_cny_display":"3.23","frozen_btc_display":"4.23","frozen_ltc_display":"5.23","loan_cny_display":"6.23","loan_btc_display":"7.23","loan_ltc_display":"8.23"}`) 91 | if err != nil { 92 | return account, err 93 | } 94 | err = json.Unmarshal(jsonBlob, &account) 95 | if err != nil { 96 | return account, err 97 | } 98 | return account, nil 99 | 100 | } 101 | 102 | /** 103 | * 获取个人账户信息(返回API的json字符串) 104 | */ 105 | func (hb *HuobiClient) GetAccountInfoJson() ([]byte, error) { 106 | p := map[string]string{"method": "get_account_info"} 107 | parameter := hb.generateParameter(p) 108 | return hb.SendTradingRequest(parameter) 109 | } 110 | 111 | /** 112 | * 获取当前所有正在进行的委托 113 | * coinType 数字货币 BTC\LTC 114 | */ 115 | func (hb *HuobiClient) GetOrders(coinType CoinT) ([]Order, error) { 116 | orders := []Order{} 117 | jsonBlob, err := hb.GetOrdersJson(coinType) 118 | if err != nil { 119 | return orders, err 120 | } 121 | err = json.Unmarshal(jsonBlob, &orders) 122 | if err != nil { 123 | return orders, err 124 | } 125 | return orders, nil 126 | } 127 | 128 | /** 129 | * 获取当前所有正在进行的委托(返回API的json字符串) 130 | * coinType 数字货币 BTC\LTC 131 | */ 132 | func (hb *HuobiClient) GetOrdersJson(coinType CoinT) ([]byte, error) { 133 | p := map[string]string{"method": "get_orders", "coin_type": formatCoinType(coinType)} 134 | parameter := hb.generateParameter(p) 135 | return hb.SendTradingRequest(parameter) 136 | } 137 | 138 | /** 139 | * 获取委托订单详情 140 | * coinType 数字货币 BTC\LTC 141 | * id 订单id 142 | */ 143 | func (hb *HuobiClient) OrderInfo(coinType CoinT, id int) (*OrderInfo, error) { 144 | orderInfo := &OrderInfo{} 145 | jsonBlob, err := hb.OrderInfoJson(coinType, id) 146 | // jsonBlob = []byte(`{"id":3748640502,"type":1,"order_price":"3000.00","order_amount":"0.0100","processed_price":"1.11","processed_amount":"2.22","vot":"3.33","fee":"4.44","total":"5.55","status":8}`) 147 | if err != nil { 148 | return orderInfo, err 149 | } 150 | err = json.Unmarshal(jsonBlob, orderInfo) 151 | if err != nil { 152 | return orderInfo, err 153 | } 154 | return orderInfo, nil 155 | } 156 | 157 | /** 158 | * 获取委托订单详情(返回API的json字符串) 159 | * coinType 数字货币 BTC\LTC 160 | * id 订单id 161 | */ 162 | func (hb *HuobiClient) OrderInfoJson(coinType CoinT, id int) ([]byte, error) { 163 | p := map[string]string{"method": "order_info", "coin_type": formatCoinType(coinType), "id": strconv.Itoa(id)} 164 | parameter := hb.generateParameter(p) 165 | return hb.SendTradingRequest(parameter) 166 | } 167 | 168 | /** 169 | * 限价买入 170 | * coinType 买入的数字货币 BTC\LTC 171 | * price 买价,期望购买的价位 172 | * amount 数字货币数量,要购买数字货币的数量 173 | */ 174 | func (hb *HuobiClient) Buy(coinType CoinT, price, amount float64) (*Result, error) { 175 | result := &Result{} 176 | jsonBlob, err := hb.BuyJson(coinType, price, amount) 177 | if err != nil { 178 | return result, err 179 | } 180 | err = json.Unmarshal(jsonBlob, result) 181 | if err != nil { 182 | return result, err 183 | } 184 | return result, nil 185 | } 186 | 187 | /** 188 | * 限价买入(返回API的json字符串) 189 | * coinType 买入的数字货币 BTC\LTC 190 | * price 买价,期望购买的价位 191 | * amount 数字货币数量,要购买数字货币的数量 192 | */ 193 | func (hb *HuobiClient) BuyJson(coinType CoinT, price, amount float64) ([]byte, error) { 194 | p := map[string]string{"method": "buy", "coin_type": formatCoinType(coinType), "price": formatPrice(price), "amount": formatCoinAmout(amount)} 195 | parameter := hb.generateParameter(p) 196 | return hb.SendTradingRequest(parameter) 197 | } 198 | 199 | /** 200 | * 限价卖出 201 | * coinType 卖出的数字货币 BTC\LTC 202 | * price 卖价,期望卖出的价位 203 | * amount 数字货币数量,卖出的coinType的数量 204 | */ 205 | func (hb *HuobiClient) Sell(coinType CoinT, price, amount float64) (*Result, error) { 206 | result := &Result{} 207 | jsonBlob, err := hb.SellJson(coinType, price, amount) 208 | if err != nil { 209 | return result, err 210 | } 211 | err = json.Unmarshal(jsonBlob, result) 212 | if err != nil { 213 | return result, err 214 | } 215 | return result, nil 216 | } 217 | 218 | /** 219 | * 限价卖出(返回API的json字符串) 220 | * coinType 卖出的数字货币 BTC\LTC 221 | * price 卖价,期望卖出的价位 222 | * amount 数字货币数量,卖出的coinType的数量 223 | */ 224 | func (hb *HuobiClient) SellJson(coinType CoinT, price, amount float64) ([]byte, error) { 225 | p := map[string]string{"method": "sell", "coin_type": formatCoinType(coinType), "price": formatPrice(price), "amount": formatCoinAmout(amount)} 226 | parameter := hb.generateParameter(p) 227 | return hb.SendTradingRequest(parameter) 228 | } 229 | 230 | /** 231 | * 市价买入 232 | * coinType 买入的数字货币 BTC\LTC 233 | * amount 法币金额。要买入多少钱的数字货币,单位CNY/USD,金额精确到0.01元,最少为1元 234 | */ 235 | func (hb *HuobiClient) BuyMarket(coinType CoinT, amount float64) (*Result, error) { 236 | result := &Result{} 237 | jsonBlob, err := hb.BuyMarketJson(coinType, amount) 238 | if err != nil { 239 | return result, err 240 | } 241 | err = json.Unmarshal(jsonBlob, result) 242 | if err != nil { 243 | return result, err 244 | } 245 | return result, nil 246 | } 247 | 248 | /** 249 | * 市价买入(返回API的json字符串) 250 | * coinType 买入的数字货币 BTC\LTC 251 | * amount 法币金额。要买入多少钱的数字货币,单位CNY/USD,金额精确到0.01元,最少为1元 252 | */ 253 | func (hb *HuobiClient) BuyMarketJson(coinType CoinT, amount float64) ([]byte, error) { 254 | p := map[string]string{"method": "buy_market", "coin_type": formatCoinType(coinType), "amount": formatPrice(amount)} 255 | parameter := hb.generateParameter(p) 256 | return hb.SendTradingRequest(parameter) 257 | } 258 | 259 | /** 260 | * 市价卖出 261 | * coinType 卖出的数字货币 BTC\LTC 262 | * amount 要卖出的btc/ltc数量,精确到0.0001个币, 但是最小卖出为0.001币(比如卖出3.1024个币) 263 | */ 264 | func (hb *HuobiClient) SellMarket(coinType CoinT, amount float64) (*Result, error) { 265 | result := &Result{} 266 | jsonBlob, err := hb.SellMarketJson(coinType, amount) 267 | if err != nil { 268 | return result, err 269 | } 270 | err = json.Unmarshal(jsonBlob, result) 271 | if err != nil { 272 | return result, err 273 | } 274 | return result, nil 275 | } 276 | 277 | /** 278 | * 市价卖出(返回API的json字符串) 279 | * coinType 卖出的数字货币 BTC\LTC 280 | * amount 要卖出的btc/ltc数量,精确到0.0001个币 281 | */ 282 | func (hb *HuobiClient) SellMarketJson(coinType CoinT, amount float64) ([]byte, error) { 283 | p := map[string]string{"method": "sell_market", "coin_type": formatCoinType(coinType), "amount": formatCoinAmout(amount)} 284 | parameter := hb.generateParameter(p) 285 | return hb.SendTradingRequest(parameter) 286 | } 287 | 288 | /** 289 | * 取消委托单 290 | * coinType 数字货币 BTC\LTC 291 | * id 要取消的委托id 292 | */ 293 | func (hb *HuobiClient) CancelOrder(coinType CoinT, id int) (*Result, error) { 294 | result := &Result{} 295 | jsonBlob, err := hb.CancelOrderJson(coinType, id) 296 | if err != nil { 297 | return result, err 298 | } 299 | err = json.Unmarshal(jsonBlob, result) 300 | if err != nil { 301 | return result, err 302 | } 303 | return result, nil 304 | } 305 | 306 | /** 307 | * 取消委托单(返回API的json字符串) 308 | * coinType 数字货币 BTC\LTC 309 | * id 要取消的委托id 310 | */ 311 | func (hb *HuobiClient) CancelOrderJson(coinType CoinT, id int) ([]byte, error) { 312 | p := map[string]string{"method": "cancel_order", "coin_type": formatCoinType(coinType), "id": strconv.Itoa(id)} 313 | parameter := hb.generateParameter(p) 314 | return hb.SendTradingRequest(parameter) 315 | } 316 | 317 | /** 318 | * 查询个人最新10条成交订单 319 | * coinType 数字货币 BTC\LTC 320 | */ 321 | func (hb *HuobiClient) GetNewDealOrders(coinType CoinT) ([]OrderTraded, error) { 322 | orders := []OrderTraded{} 323 | jsonBlob, err := hb.GetNewDealOrdersJson(coinType) 324 | if err != nil { 325 | return orders, err 326 | } 327 | err = json.Unmarshal(jsonBlob, &orders) 328 | if err != nil { 329 | return orders, err 330 | } 331 | return orders, nil 332 | } 333 | 334 | /** 335 | * 查询个人最新10条成交订单(返回API的json字符串) 336 | * coinType 数字货币 BTC\LTC 337 | */ 338 | func (hb *HuobiClient) GetNewDealOrdersJson(coinType CoinT) ([]byte, error) { 339 | p := map[string]string{"method": "get_new_deal_orders", "coin_type": formatCoinType(coinType)} 340 | parameter := hb.generateParameter(p) 341 | return hb.SendTradingRequest(parameter) 342 | } 343 | 344 | /** 345 | * 发送交易请求到api接口获取数据,用于发起需要用户交易秘钥的请求 346 | */ 347 | func (hb *HuobiClient) SendTradingRequest(parameter string) ([]byte, error) { 348 | if len(hb.accessKey) < 20 || len(hb.secretKey) < 20 { 349 | return []byte{}, errors.New("error!the huobi AccessKey and SecretKey is incorrect.") 350 | } 351 | 352 | url := API_V3_URI 353 | return hb.SendRequest(url, parameter) 354 | } 355 | 356 | /** 357 | * 发送请求到api接口获取数据 358 | * uri 请求的uri 359 | * parameter 请求的数据 360 | */ 361 | func (hb *HuobiClient) SendRequest(uri, parameter string) ([]byte, error) { 362 | body := ioutil.NopCloser(strings.NewReader(parameter)) //把form数据编码 363 | req, _ := http.NewRequest("POST", uri, body) 364 | req.Header.Set("Content-Type", "application/x-www-form-urlencoded; param=value") //post方式需要 365 | req.Header.Add("User-Agent", hb.userAgent) 366 | resp, err := hb.httpClient.Do(req) //发送请求 367 | data := []byte{} 368 | if err != nil { 369 | return data, err 370 | } 371 | defer resp.Body.Close() //一定要关闭resp.Body 372 | return ioutil.ReadAll(resp.Body) 373 | } 374 | 375 | func checkErr(err error) { 376 | if err != nil { 377 | fmt.Println(err.Error()) 378 | } 379 | } 380 | 381 | /** 382 | * 格式价格为string,最大2位小数。hubi的金额精确到2位小数 383 | * 所有提交post的参数均为string类型 384 | */ 385 | func formatPrice(price float64) string { 386 | return strconv.FormatFloat(price, 'f', 2, 64) 387 | } 388 | 389 | /** 390 | * 格式化比特币数量为string,最大4位小数。huobi所有币种精确到4位小数 391 | * 所有提交post的参数均为string类型 392 | */ 393 | func formatCoinAmout(amount float64) string { 394 | return strconv.FormatFloat(amount, 'f', 4, 64) 395 | } 396 | 397 | /** 398 | * 格式化数字货币类型为string。 399 | * 所有提交post的参数均为string类型 400 | */ 401 | func formatCoinType(coinType CoinT) string { 402 | return strconv.Itoa(int(coinType)) 403 | } 404 | --------------------------------------------------------------------------------