From 0e37811cd05c98525e74afb4056df94f165aae4d Mon Sep 17 00:00:00 2001 From: Adrian Gallagher Date: Wed, 29 Oct 2014 23:27:55 +1100 Subject: [PATCH] Add base files for various cryptocurrency exchanges. --- bitfinexhttp.go | 331 ++++++++++++++++++++++++++++++++++++++++++++++++ bitstamphttp.go | 249 ++++++++++++++++++++++++++++++++++++ btcchinahttp.go | 161 +++++++++++++++++++++++ btcehttp.go | 146 +++++++++++++++++++++ common.go | 37 ++++++ itbithttp.go | 235 ++++++++++++++++++++++++++++++++++ okcoinhttp.go | 184 +++++++++++++++++++++++++++ 7 files changed, 1343 insertions(+) create mode 100644 bitfinexhttp.go create mode 100644 bitstamphttp.go create mode 100644 btcchinahttp.go create mode 100644 btcehttp.go create mode 100644 common.go create mode 100644 itbithttp.go create mode 100644 okcoinhttp.go diff --git a/bitfinexhttp.go b/bitfinexhttp.go new file mode 100644 index 00000000..b3f9c2e8 --- /dev/null +++ b/bitfinexhttp.go @@ -0,0 +1,331 @@ +package main + +import ( + "net/http" + "io/ioutil" + "fmt" + "encoding/json" + "encoding/hex" + "crypto/hmac" + "crypto/sha512" + "encoding/base64" + "errors" + "strings" + "strconv" + "time" +) + +const ( + BITFINEX_API_URL = "https://api.bitfinex.com/v1/" + BITFINEX_TICKER = "pubticker/" + BITFINEX_STATS = "stats/" + BITFINEX_ORDERBOOK = "book/" + BITFINEX_TRADES = "trades/" + BITFINEX_SYMBOLS = "symbols/" + BITFINEX_SYMBOLS_DETAILS = "symbols_details/" + BITFINEX_DEPOSIT = "deposit/new" + BITFINEX_ORDER_NEW = "order/new" + BITFINEX_ORDER_CANCEL = "order/cancel" + BITFINEX_ORDER_CANCEL_ALL = "order/cancel/all" + BITFINEX_ORDER_STATUS = "order/status" + BITFINEX_ORDERS = "orders" + BITFINEX_POSITIONS = "positions" + BITFINEX_CLAIM_POSITION = "position/claim" + BITFINEX_HISTORY = "history" + BITFINEX_TRADE_HISTORY = "mytrades" +) + +type BitfinexStats struct { + Period int64 + Volume string +} + +type BitfinexTicker struct { + Mid, Bid, Ask, Last_price, Low, High, Volume, Timestamp string +} + +type BookStructure struct { + Price, Amount, Timestamp string +} + +type BitfinexOrderbook struct { + Bids []BookStructure + Asks []BookStructure +} + +type TradeStructure struct { + Timestamp, Tid int64 + Price, Amount, Exchange, Type string +} + +type SymbolsDetails struct { + Pair, Initial_margin, Minimum_margin, Maximum_order_size, Minimum_order_size, Expiration string + Price_precision int +} + +type Bitfinex struct { + APIKey, APISecret string + Ticker BitfinexTicker + Stats []BitfinexStats + Orderbook BitfinexOrderbook + Trades []TradeStructure + SymbolsDetails []SymbolsDetails +} + +func (b *Bitfinex) SendAuthenticatedHTTPRequest(path string, params map[string]interface{}) (err error) { + request := make(map[string]interface{}) + request["request"] = "/v1/" + path + request["nonce"] = strconv.FormatInt(time.Now().UnixNano(), 10) + + if params != nil { + for key, value:= range params { + request[key] = value + } + } + + PayloadJson, err := json.Marshal(request) + fmt.Printf("Request JSON: %s\n", PayloadJson) + + if err != nil { + return errors.New("SendAuthenticatedHTTPRequest: Unable to JSON request") + } + + PayloadBase64 := base64.StdEncoding.EncodeToString(PayloadJson) + fmt.Printf("Base64: %s\n", PayloadBase64) + + hmac := hmac.New(sha512.New384, []byte(b.APISecret)) + hmac.Write([]byte(PayloadBase64)) + signature := hex.EncodeToString(hmac.Sum(nil)) + method := "GET" + + if strings.Contains(path, BITFINEX_ORDER_CANCEL_ALL) { + method = "POST" + } + + req, err := http.NewRequest(method, BITFINEX_API_URL + path, strings.NewReader("")) + req.Header.Set("X-BFX-APIKEY", string(b.APIKey)) + req.Header.Set("X-BFX-PAYLOAD", PayloadBase64) + req.Header.Set("X-BFX-SIGNATURE", signature) + + client := &http.Client{} + resp, err := client.Do(req) + + if err != nil { + return errors.New("SendAuthenticatedHTTPRequest: Unable to send request") + } + + contents, _ := ioutil.ReadAll(resp.Body) + fmt.Printf("Recieved raw: %s\n", string(contents)) + resp.Body.Close() + return nil +} + +func (b *Bitfinex) GetTicker(symbol string) (bool) { + err := SendHTTPRequest(BITFINEX_API_URL + BITFINEX_TICKER + symbol, true, &b.Ticker) + if err != nil { + fmt.Println(err) + return false + } + return true +} + +func (b *Bitfinex) GetStats(symbol string) (bool) { + err := SendHTTPRequest(BITFINEX_API_URL + BITFINEX_STATS + symbol, true, &b.Stats) + if err != nil { + fmt.Println(err) + return false + } + return true +} + +func (b *Bitfinex) GetOrderbook(symbol string) (bool) { + err := SendHTTPRequest(BITFINEX_API_URL + BITFINEX_ORDERBOOK + symbol, true, &b.Orderbook) + if err != nil { + fmt.Println(err) + return false + } + return true +} + +func (b *Bitfinex) GetTrades(symbol string) (bool) { + err := SendHTTPRequest(BITFINEX_API_URL + BITFINEX_TRADES + symbol, true, &b.Trades) + if err != nil { + fmt.Println(err) + return false + } + return true +} + +func (b *Bitfinex) GetSymbols() (bool) { + err := SendHTTPRequest(BITFINEX_API_URL + BITFINEX_SYMBOLS, false, nil) + if err != nil { + fmt.Println(err) + return false + } + return true +} + +func (b *Bitfinex) GetSymbolsDetails() (bool) { + err := SendHTTPRequest(BITFINEX_API_URL + BITFINEX_SYMBOLS_DETAILS, false, &b.SymbolsDetails) + if err != nil { + fmt.Println(err) + return false + } + return true +} + +func (b *Bitfinex) NewDeposit(Symbol, Method, Wallet string) { + request := make(map[string]interface{}) + request["currency"] = Symbol + request["method"] = Method + request["wallet_name"] = Wallet + + err := b.SendAuthenticatedHTTPRequest(BITFINEX_DEPOSIT, request) + + if err != nil { + fmt.Println(err) + } +} + +func (b *Bitfinex) NewOrder(Symbol string, Amount float64, Price float64, Buy bool, Type string, Hidden bool) { + request := make(map[string]interface{}) + request["symbol"] = Symbol + request["amount"] = fmt.Sprintf("%.8f", Amount) + request["price"] = fmt.Sprintf("%.5f", Price) + request["exchange"] = "bitfinex" + + if Buy { + request["side"] = "buy" + } else { + request["side"] = "sell" + } + + //request["is_hidden"] - currently not implemented + request["type"] = Type + + err := b.SendAuthenticatedHTTPRequest(BITFINEX_ORDER_NEW, request) + + if err != nil { + fmt.Println(err) + } +} + +func (b *Bitfinex) CancelOrder(OrderID int) { + request := make(map[string]interface{}) + request["order_id"] = OrderID + + err := b.SendAuthenticatedHTTPRequest(BITFINEX_ORDER_CANCEL, request) + + if err != nil { + fmt.Println(err) + } +} + +func (b *Bitfinex) CancelMultiplateOrders(OrderIDs []int) { + request := make(map[string]interface{}) + request["order_ids"] = OrderIDs + + err := b.SendAuthenticatedHTTPRequest(BITFINEX_ORDER_CANCEL, request) + + if err != nil { + fmt.Println(err) + } +} + +func (b *Bitfinex) CancelAllOrders() { + err := b.SendAuthenticatedHTTPRequest(BITFINEX_ORDER_CANCEL_ALL, nil) + + if err != nil { + fmt.Println(err) + } +} + +func (b *Bitfinex) ReplaceOrder(OrderID int) { + request := make(map[string]interface{}) + request["order_id"] = OrderID +} + +func (b *Bitfinex) GetOrderStatus(OrderID int) { + request := make(map[string]interface{}) + request["order_id"] = OrderID + + err := b.SendAuthenticatedHTTPRequest(BITFINEX_ORDER_STATUS, request) + + if err != nil { + fmt.Println(err) + } +} + +func (b *Bitfinex) GetActiveOrders() { + err := b.SendAuthenticatedHTTPRequest(BITFINEX_ORDERS, nil) + + if err != nil { + fmt.Println(err) + } +} + +func (b *Bitfinex) GetActivePositions() { + err := b.SendAuthenticatedHTTPRequest(BITFINEX_POSITIONS, nil) + + if err != nil { + fmt.Println(err) + } +} + +func (b *Bitfinex) ClaimPosition(PositionID int) { + request := make(map[string]interface{}) + request["position_id"] = PositionID + + err := b.SendAuthenticatedHTTPRequest(BITFINEX_CLAIM_POSITION, nil) + + if err != nil { + fmt.Println(err) + } +} + +func (b *Bitfinex) GetBalanceHistory(symbol string, timeSince time.Time, timeUntil time.Time, limit int, wallet string) { + request := make(map[string]interface{}) + request["currency"] = symbol + request["since"] = timeSince + request["until"] = timeUntil + + if limit > 0 { + request["limit"] = limit + } + + if len(wallet) > 0 { + request["wallet"] = wallet + } + + err := b.SendAuthenticatedHTTPRequest(BITFINEX_HISTORY, request) + + if err != nil { + fmt.Println(err) + } +} + +func (b *Bitfinex) GetTradeHistory(symbol string, timestamp time.Time, limit int) { + request := make(map[string]interface{}) + request["currency"] = symbol + request["timestamp"] = timestamp + + if (limit > 0) { + request["limit_trades"] = limit + } + + err := b.SendAuthenticatedHTTPRequest(BITFINEX_TRADE_HISTORY, nil) + + if err != nil { + fmt.Println(err) + } +} + +func JsonDecode(data string, result interface{}) (err error) { + r := json.NewDecoder(strings.NewReader(data)) + err = r.Decode(result) + + if err != nil { + return err + } + return +} \ No newline at end of file diff --git a/bitstamphttp.go b/bitstamphttp.go new file mode 100644 index 00000000..f5884df2 --- /dev/null +++ b/bitstamphttp.go @@ -0,0 +1,249 @@ +package main + +import ( + "net/http" + "net/url" + "io/ioutil" + "fmt" + "encoding/hex" + "crypto/hmac" + "crypto/sha256" + "strings" + "strconv" + "errors" + "time" +) + +const ( + BITSTAMP_API_URL = "https://www.bitstamp.net/api/" + BITSTAMP_API_TICKER = "ticker/" + BITSTAMP_API_ORDERBOOK = "order_book/" + BITSTAMP_API_TRANSACTIONS = "transactions/" + BITSTAMP_API_EURUSD = "eur_usd/" + BITSTAMP_API_BALANCE = "balance/" + BITSTAMP_API_USER_TRANSACTIONS = "user_transactions/" + BITSTAMP_API_OPEN_ORDERS = "open_orders/" + BITSTAMP_API_CANCEL_ORDER = "cancel_order/" + BITSTAMP_API_BUY = "buy/" + BITSTAMP_API_SELL = "sell/" + BITSTAMP_API_WITHDRAWAL_REQUESTS = "withdrawal_requests/" + BITSTAMP_API_BITCOIN_WITHDRAWAL = "bitcoin_withdrawal/" + BITSTAMP_API_BITCOIN_DEPOSIT = "bitcoin_deposit_address/" + BITSTAMP_API_UNCONFIRMED_BITCOIN = "unconfirmed_btc/" + BITSTAMP_API_RIPPLE_WITHDRAWAL = "ripple_withdrawal/" + BITSTAMP_API_RIPPLE_DESPOIT = "ripple_address/" +) + +type Bitstamp struct { + ClientID, APIKey, APISecret string + Ticker BitstampTicker + Orderbook Orderbook + ConversionRate ConversionRate + Transactions []Transactions +} + +type BitstampTicker struct { + Last, High, Low, Vwap, Volume, Bid, Ask string +} + +type Orderbook struct { + Timestamp string + Bids [][]string + Asks [][]string +} + +type Transactions struct { + Date, Price, Amount string + Tid int64 +} + +type ConversionRate struct { + Buy string + Sell string +} + +func (b *Bitstamp) GetTicker() { + err := SendHTTPRequest(BITSTAMP_API_URL + BITSTAMP_API_TICKER, true, &b.Ticker) + + if err != nil { + fmt.Println(err) + return + } +} + +func (b *Bitstamp) GetOrderbook() { + err := SendHTTPRequest(BITSTAMP_API_URL + BITSTAMP_API_ORDERBOOK, true, &b.Orderbook) + + if err != nil { + fmt.Println(err) + return + } +} + +func (b *Bitstamp) GetTransactions() { + err := SendHTTPRequest(BITSTAMP_API_URL + BITSTAMP_API_TRANSACTIONS, true, &b.Transactions) + + if err != nil { + fmt.Println(err) + return + } +} + +func (b *Bitstamp) GetEURUSDConversionRate() { + err := SendHTTPRequest(BITSTAMP_API_URL + BITSTAMP_API_EURUSD, true, &b.ConversionRate) + + if err != nil { + fmt.Println(err) + return + } +} + +func (b *Bitstamp) GetBalance() { + err := b.SendAuthenticatedHTTPRequest(BITSTAMP_API_BALANCE, url.Values{}) + + if err != nil { + fmt.Println(err) + } +} + +func (b *Bitstamp) GetUserTransactions(offset, limit, sort int64) { + var req = url.Values{} + + req.Add("offset", strconv.FormatInt(offset, 10)) + req.Add("limit", strconv.FormatInt(limit, 10)) + req.Add("sort", strconv.FormatInt(sort, 10)) + + err := b.SendAuthenticatedHTTPRequest(BITSTAMP_API_USER_TRANSACTIONS, req) + + if err != nil { + fmt.Println(err) + } +} + +func (b *Bitstamp) CancelOrder(OrderID int64) { + var req = url.Values{} + req.Add("id", strconv.FormatInt(OrderID, 10)) + + err := b.SendAuthenticatedHTTPRequest(BITSTAMP_API_CANCEL_ORDER, req) + + if err != nil { + fmt.Println(err) + } +} + +func (b *Bitstamp) GetOpenOrders() { + err := b.SendAuthenticatedHTTPRequest(BITSTAMP_API_OPEN_ORDERS, url.Values{}) + + if err != nil { + fmt.Println(err) + } +} + +func (b *Bitstamp) PlaceOrder(price float64, amount float64, Type int) { + var req = url.Values{} + req.Add("amount", strconv.FormatFloat(amount, 'f', 8, 64)) + req.Add("price", strconv.FormatFloat(price, 'f', 2, 64)) + orderType := BITSTAMP_API_BUY + + if Type == 1 { + orderType = BITSTAMP_API_SELL + } + + fmt.Printf("Placing %s order at price %f for %f amount.\n", orderType, price, amount) + + err := b.SendAuthenticatedHTTPRequest(orderType, req) + + if err != nil { + fmt.Println(err) + } +} + +func (b *Bitstamp) GetWithdrawalRequests() { + err := b.SendAuthenticatedHTTPRequest(BITSTAMP_API_WITHDRAWAL_REQUESTS, url.Values{}) + + if err != nil { + fmt.Println(err) + } +} + +func (b *Bitstamp) BitcoinWithdrawal(amount float64, address string) { + var req = url.Values{} + req.Add("amount", strconv.FormatFloat(amount, 'f', 8, 64)) + req.Add("address", address) + + err := b.SendAuthenticatedHTTPRequest(BITSTAMP_API_BITCOIN_WITHDRAWAL, req) + + if err != nil { + fmt.Println(err) + } +} + +func (b *Bitstamp) BitcoinDepositAddress() { + err := b.SendAuthenticatedHTTPRequest(BITSTAMP_API_BITCOIN_DEPOSIT, url.Values{}) + + if err != nil { + fmt.Println(err) + } +} + +func (b *Bitstamp) UnconfirmedBitcoin() { + err := b.SendAuthenticatedHTTPRequest(BITSTAMP_API_UNCONFIRMED_BITCOIN, url.Values{}) + + if err != nil { + fmt.Println(err) + } +} + +func (b *Bitstamp) RippleWithdrawal(amount float64, address, currency string) { + var req = url.Values{} + req.Add("amount", strconv.FormatFloat(amount, 'f', 8, 64)) + req.Add("address", address) + req.Add("currency", currency) + + err := b.SendAuthenticatedHTTPRequest(BITSTAMP_API_RIPPLE_WITHDRAWAL, req) + + if err != nil { + fmt.Println(err) + } +} + +func (b *Bitstamp) RippleDepositAddress() { + err := b.SendAuthenticatedHTTPRequest(BITSTAMP_API_RIPPLE_DESPOIT, url.Values{}) + + if err != nil { + fmt.Println(err) + } +} + +func (b *Bitstamp) SendAuthenticatedHTTPRequest(path string, values url.Values) (err error) { + nonce := strconv.FormatInt(time.Now().UnixNano(), 10) + values.Set("key", b.APIKey) + values.Set("nonce", nonce) + hmac := hmac.New(sha256.New, []byte(b.APISecret)) + hmac.Write([]byte(nonce + b.ClientID + b.APIKey)) + values.Set("signature", strings.ToUpper(hex.EncodeToString(hmac.Sum(nil)))) + + reqBody := strings.NewReader(values.Encode()) + + path = BITSTAMP_API_URL + path + fmt.Println("Sending POST request to " + path) + + req, err := http.NewRequest("POST", path, reqBody) + if err != nil { + return err + } + + req.Header.Add("Content-Type", "application/x-www-form-urlencoded") + + client := &http.Client{} + resp, err := client.Do(req) + + if err != nil { + return errors.New("PostRequest: Unable to send request") + } + + contents, _ := ioutil.ReadAll(resp.Body) + fmt.Printf("Recieved raw: %s\n", string(contents)) + resp.Body.Close() + return nil +} \ No newline at end of file diff --git a/btcchinahttp.go b/btcchinahttp.go new file mode 100644 index 00000000..8f8bd1e3 --- /dev/null +++ b/btcchinahttp.go @@ -0,0 +1,161 @@ +package main + +import ( + "net/http" + "net/url" + "strconv" + "crypto/hmac" + "crypto/sha1" + "encoding/base64" + "encoding/hex" + "encoding/json" + "errors" + "strings" + "time" + "io/ioutil" + "fmt" +) + +const ( + BTCCHINA_API_URL = "https://api.btcchina.com/" +) + +type BTCChina struct { + APISecret, APIKey string +} + +func (b *BTCChina) GetTicker(symbol string) (bool) { + req := fmt.Sprintf("%sdata/ticker?market=%s", BTCCHINA_API_URL, symbol) + err := SendHTTPRequest(req, true, nil) + if err != nil { + fmt.Println(err) + return false + } + return true +} + +func (b *BTCChina) GetTradesLast24h(symbol string) (bool) { + req := fmt.Sprintf("%sdata/trades?market=%s", BTCCHINA_API_URL, symbol) + err := SendHTTPRequest(req, true, nil) + if err != nil { + fmt.Println(err) + return false + } + return true +} + +func (b *BTCChina) GetTradeHistory(symbol string, limit, sinceTid int64, time time.Time) (bool) { + req := fmt.Sprintf("%sdata/historydata?market=%s", BTCCHINA_API_URL, symbol) + v := url.Values{} + + if limit > 0 { + v.Set("limit", strconv.FormatInt(limit, 10)) + } + if sinceTid > 0 { + v.Set("since", strconv.FormatInt(sinceTid, 10)) + } + if !time.IsZero() { + v.Set("sincetype", strconv.FormatInt(time.Unix(), 10)) + } + + values := v.Encode() + if (len(values) > 0) { + req += "?" + values + } + + err := SendHTTPRequest(req, true, nil) + if err != nil { + fmt.Println(err) + return false + } + return true +} + +func (b *BTCChina) GetOrderBook(symbol string, limit int) (bool) { + req := fmt.Sprintf("%sdata/orderbook?market=%s&limit=%d", BTCCHINA_API_URL, symbol, limit) + err := SendHTTPRequest(req, true, nil) + if err != nil { + fmt.Println(err) + return false + } + return true +} + +func (b *BTCChina) GetAccountInfo() { + err := b.SendAuthenticatedHTTPRequest("getAccountInfo", nil) + + if err != nil { + fmt.Println(err) + } +} + +func (b *BTCChina) BuyOrder(price, amount float64) { + params := []string{} + + if (price != 0) { + params = append(params, strconv.FormatFloat(price, 'f', 8, 64)) + } + + err := b.SendAuthenticatedHTTPRequest("buyOrder2", nil) + + if err != nil { + fmt.Println(err) + } +} + +func (b *BTCChina) SendAuthenticatedHTTPRequest(method string, params []string) (err error) { + nonce := strconv.FormatInt(time.Now().UnixNano(), 10)[0:16] + + if (len(params) > 0) { + params = nil + } + + encoded := fmt.Sprintf("tonce=%s&accesskey=%s&requestmethod=post&id=%d&method=%s¶ms=%s", nonce, b.APIKey, 1, method, params) + + fmt.Println(encoded) + + hmac := hmac.New(sha1.New, []byte(b.APISecret)) + hmac.Write([]byte(encoded)) + hash := hex.EncodeToString(hmac.Sum(nil)) + + postData := make(map[string]interface{}) + postData["method"] = method + postData["params"] = []string{} + postData["id"] = 1 + + data, err := json.Marshal(postData) + + fmt.Println(string(data)) + + if err != nil { + return errors.New("Unable to JSON POST data") + } + + fmt.Printf("Sending POST request to %s calling method %s with params %s\n", "https://api.btcchina.com/api_trade_v1.php", method, data) + reqBody := strings.NewReader(string(data)) + + b64 := base64.StdEncoding.EncodeToString([]byte(b.APIKey + ":" + hash)) + + req, err := http.NewRequest("POST", "https://api.btcchina.com/api_trade_v1.php", reqBody) + + if err != nil { + return err + } + + req.Header.Add("Content-type", "application/json-rpc") + req.Header.Add("Authorization", "Basic " + b64) + req.Header.Add("Json-Rpc-Tonce", nonce) + + client := &http.Client{} + resp, err := client.Do(req) + + if err != nil { + return errors.New("PostRequest: Unable to send request") + } + + contents, _ := ioutil.ReadAll(resp.Body) + fmt.Printf("Recv'd :%s", string(contents)) + resp.Body.Close() + return nil + +} \ No newline at end of file diff --git a/btcehttp.go b/btcehttp.go new file mode 100644 index 00000000..945bf528 --- /dev/null +++ b/btcehttp.go @@ -0,0 +1,146 @@ +package main + +import ( + "net/http" + "net/url" + "strconv" + "crypto/hmac" + "crypto/sha512" + "encoding/hex" + "errors" + "strings" + "time" + "io/ioutil" + "fmt" +) + +const ( + BTCE_API_URL = "https://btc-e.com/tapi" + BTCE_GET_INFO = "getInfo" + BTCE_TRANSACTION_HISTORY = "TransHistory" + BTCE_TRADE_HISTORY = "TradeHistory" + BTCE_ACTIVE_ORDERS = "ActiveOrders" + BTCE_TRADE = "Trade" + BTCE_CANCEL_ORDER = "CancelOrder" +) + +type BTCE struct { + APIKey, APISecret string +} + +func (b *BTCE) GetInfo() { + err := b.SendAuthenticatedHTTPRequest(BTCE_GET_INFO, url.Values{}) + + if err != nil { + fmt.Println(err) + } +} + +func (b *BTCE) GetActiveOrders(pair string) { + req := url.Values{} + req.Add("pair", pair) + + err := b.SendAuthenticatedHTTPRequest(BTCE_ACTIVE_ORDERS, req) + + if err != nil { + fmt.Println(err) + } +} + +func (b *BTCE) CancelOrder(OrderID int64) { + req := url.Values{} + req.Add("order_id", strconv.FormatInt(OrderID, 10)) + + err := b.SendAuthenticatedHTTPRequest(BTCE_CANCEL_ORDER, req) + + if err != nil { + fmt.Println(err) + } +} + +func (b *BTCE) Trade(pair, orderType string, amount, price float64) { + req := url.Values{} + req.Add("pair", pair) + req.Add("type", orderType) + req.Add("amount", strconv.FormatFloat(amount, 'f', 8, 64)) + req.Add("rate", strconv.FormatFloat(price, 'f', 2, 64)) + + err := b.SendAuthenticatedHTTPRequest(BTCE_TRADE, req) + + if err != nil { + fmt.Println(err) + } +} + +func (b *BTCE) GetTransactionHistory(TIDFrom, Count, TIDEnd int64, order, since, end string) { + req := url.Values{} + req.Add("from", strconv.FormatInt(TIDFrom, 10)) + req.Add("count", strconv.FormatInt(Count, 10)) + req.Add("from_id", strconv.FormatInt(TIDFrom, 10)) + req.Add("end_id", strconv.FormatInt(TIDFrom, 10)) + req.Add("order", order) + req.Add("since", order) + req.Add("end", order) + + err := b.SendAuthenticatedHTTPRequest(BTCE_TRANSACTION_HISTORY, req) + + if err != nil { + fmt.Println(err) + } +} + +func (b *BTCE) GetTradeHistory(TIDFrom, Count, TIDEnd int64, order, since, end, pair string) { + req := url.Values{} + + req.Add("from", strconv.FormatInt(TIDFrom, 10)) + req.Add("count", strconv.FormatInt(Count, 10)) + req.Add("from_id", strconv.FormatInt(TIDFrom, 10)) + req.Add("end_id", strconv.FormatInt(TIDFrom, 10)) + req.Add("order", order) + req.Add("since", order) + req.Add("end", order) + req.Add("pair", pair) + + err := b.SendAuthenticatedHTTPRequest(BTCE_TRANSACTION_HISTORY, req) + + if err != nil { + fmt.Println(err) + } +} + +func (b *BTCE) SendAuthenticatedHTTPRequest(method string, values url.Values) (err error) { + nonce := strconv.FormatInt(time.Now().Unix(), 10) + values.Set("nonce", nonce) + values.Set("method", method) + + hmac := hmac.New(sha512.New, []byte(b.APISecret)) + encoded := values.Encode() + hmac.Write([]byte(encoded)) + + + fmt.Printf("Sending POST request to %s calling method %s with params %s\n", BTCE_API_URL, method, encoded) + reqBody := strings.NewReader(encoded) + + req, err := http.NewRequest("POST", BTCE_API_URL, reqBody) + + if err != nil { + return err + } + + req.Header.Add("Key", b.APIKey) + req.Header.Add("Sign", hex.EncodeToString(hmac.Sum(nil))) + req.Header.Add("Content-Type", "application/x-www-form-urlencoded") + + client := &http.Client{} + resp, err := client.Do(req) + + if err != nil { + return errors.New("PostRequest: Unable to send request") + } + + contents, _ := ioutil.ReadAll(resp.Body) + fmt.Printf("Recieved raw: %s\n", string(contents)) + resp.Body.Close() + return nil + +} \ No newline at end of file diff --git a/common.go b/common.go new file mode 100644 index 00000000..3cf6dee0 --- /dev/null +++ b/common.go @@ -0,0 +1,37 @@ +package main + +import ( + "net/http" + "fmt" + "io/ioutil" + "errors" +) + +func SendHTTPRequest(url string, jsonDecode bool, result interface{}) (err error) { + res, err := http.Get(url) + fmt.Println("Attempting connection to: " + url) + + if err != nil { + fmt.Println(err) + return err + } + + if res.StatusCode != 200 { + fmt.Printf("HTTP status code: %d", res.StatusCode) + return errors.New("Status code was not 200.") + } + + contents, _ := ioutil.ReadAll(res.Body) + fmt.Printf("Recieved raw: %s\n", string(contents)) + + if jsonDecode { + err = JsonDecode(string(contents), result) + + if err != nil { + return errors.New("Unable to JSON decode body.") + } + } else { + result = contents + } + return +} diff --git a/itbithttp.go b/itbithttp.go new file mode 100644 index 00000000..8ef5104c --- /dev/null +++ b/itbithttp.go @@ -0,0 +1,235 @@ +package main + +import ( + "net/http" + "strconv" + "crypto/hmac" + "crypto/sha512" + "encoding/base64" + "encoding/hex" + "errors" + "strings" + "time" + "encoding/json" + "io/ioutil" + "fmt" +) + +const ( + ITBIT_API_URL = "https://api.itbit.com/v1/" +) + +type ItBit struct { + ClientKey, APISecret, UserID string +} + +func (i *ItBit) GetTicker(currency string) (bool) { + path := ITBIT_API_URL + "/markets/" + currency + "/ticker" + err := SendHTTPRequest(path, true, nil) + if err != nil { + fmt.Println(err) + return false + } + return true +} + +func (i *ItBit) GetOrderbook(currency string) (bool) { + path := ITBIT_API_URL + "/markets/" + currency + "/orders" + err := SendHTTPRequest(path , true, nil) + if err != nil { + fmt.Println(err) + return false + } + return true +} + +func (i *ItBit) GetTradeHistory(currency, timestamp string) (bool) { + req := "/trades?since=" + timestamp + err := SendHTTPRequest(ITBIT_API_URL + "markets/" + currency + req, true, nil) + if err != nil { + fmt.Println(err) + return false + } + return true +} + +func (i *ItBit) GetWallets(page int64, perPage int64, userID string) { + path := ITBIT_API_URL + "wallets/" + params := make(map[string]interface{}) + params["page"] = strconv.FormatInt(page, 10) + params["perPage"] = strconv.FormatInt(perPage, 10) + params["userID"] = userID + + err := i.SendAuthenticatedHTTPRequest("GET", path, params) + + if err != nil { + fmt.Println(err) + } +} + +func (i *ItBit) GetWallet(walletID string) { + path := ITBIT_API_URL + "/wallets/" + walletID + err := i.SendAuthenticatedHTTPRequest("GET", path, nil) + + if err != nil { + fmt.Println(err) + } +} + +func (i *ItBit) GetWalletBalance(walletID, currency string) { + path := ITBIT_API_URL + "/wallets/ " + walletID + "/balances/" + currency + err := i.SendAuthenticatedHTTPRequest("GET", path, nil) + + if err != nil { + fmt.Println(err) + } +} + +func (i *ItBit) GetWalletTrades(walletID string, page int64, perPage int64, rangeEnd int64, rangeStart int64) { + path := ITBIT_API_URL + "/wallets/" + walletID + "/trades" + params := make(map[string]interface{}) + params["page"] = strconv.FormatInt(page, 10) + params["perPage"] = strconv.FormatInt(perPage, 10) + params["rangeEnd"] = strconv.FormatInt(page, 10) + params["rangeStart"] = strconv.FormatInt(perPage, 10) + + err := i.SendAuthenticatedHTTPRequest("GET", path, params) + + if err != nil { + fmt.Println(err) + } +} + +func (i *ItBit) GetWalletOrders(walletID string, instrument string, page int64, perPage int64, status string) { + path := ITBIT_API_URL + "/wallets/" + walletID + "/orders" + params := make(map[string]interface{}) + params["instrument"] = instrument + params["page"] = strconv.FormatInt(page, 10) + params["perPage"] = strconv.FormatInt(perPage, 10) + params["status"] = status + + err := i.SendAuthenticatedHTTPRequest("GET", path, params) + + if err != nil { + fmt.Println(err) + } +} + +func (i *ItBit) PlaceWalletOrder(walletID, side, orderType, currency string, amount, price float64, instrument string) { + path := ITBIT_API_URL + "/wallets/" + walletID + "/orders" + params := make(map[string]interface{}) + params["side"] = side + params["type"] = orderType + params["currency"] = currency + params["amount"] = strconv.FormatFloat(amount, 'f', 8, 64) + params["price"] = strconv.FormatFloat(price, 'f', 2, 64) + params["instrument"] = instrument + + err := i.SendAuthenticatedHTTPRequest("POST", path, params) + + if err != nil { + fmt.Println(err) + } +} + +func (i *ItBit) GetWalletOrder(walletID, orderID string) { + path := ITBIT_API_URL + "/wallets/" + walletID + "/orders/" + orderID + err := i.SendAuthenticatedHTTPRequest("GET", path, nil) + + if err != nil { + fmt.Println(err) + } +} + +func (i *ItBit) CancelWalletOrder(walletID, orderID string) { + path := ITBIT_API_URL + "/wallets/" + walletID + "/orders/" + orderID + err := i.SendAuthenticatedHTTPRequest("DELETE", path, nil) + + if err != nil { + fmt.Println(err) + } +} + +func (i *ItBit) PlaceWithdrawalRequest(walletID, currency, address string, amount float64) { + path := ITBIT_API_URL + "/wallets/" + walletID + "/cryptocurrency_withdrawals" + params := make(map[string]interface{}) + params["currency"] = currency + params["amount"] = strconv.FormatFloat(amount, 'f', 8, 64) + params["address"] = address + + err := i.SendAuthenticatedHTTPRequest("POST", path, params) + + if err != nil { + fmt.Println(err) + } +} + +func (i *ItBit) GetDepositAddress(walletID, currency string) { + path := ITBIT_API_URL + "/wallets/" + walletID + "/cryptocurrency_deposits" + params := make(map[string]interface{}) + params["currency"] = currency + + err := i.SendAuthenticatedHTTPRequest("POST", path, params) + + if err != nil { + fmt.Println(err) + } +} + +func (i *ItBit) WalletTransfer(walletID, sourceWallet, destWallet string, amount float64, currency string) { + path := ITBIT_API_URL + "/wallets/" + walletID + "/wallet_transfers" + params := make(map[string]interface{}) + params["sourceWalletId"] = sourceWallet + params["destinationWalletId"] = destWallet + params["amount"] = strconv.FormatFloat(amount, 'f', 8, 64) + params["currencyCode"] = currency + + err := i.SendAuthenticatedHTTPRequest("POST", path, params) + + if err != nil { + fmt.Println(err) + } +} + +func (i *ItBit) SendAuthenticatedHTTPRequest(method string, path string, params map[string]interface{}) (err error) { + request := make(map[string]interface{}) + nonce := strconv.FormatInt(time.Now().UnixNano(), 10) + request["nonce"] = nonce + request["timestamp"] = nonce + + if params != nil { + for key, value:= range params { + request[key] = value + } + } + + PayloadJson, err := json.Marshal(request) + fmt.Printf("Request JSON: %s\n", PayloadJson) + + if err != nil { + return errors.New("SendAuthenticatedHTTPRequest: Unable to JSON request") + } + + hmac := hmac.New(sha512.New, []byte(i.APISecret)) + hmac.Write([]byte(nonce + string(PayloadJson))) + hex := hex.EncodeToString(hmac.Sum(nil)) + signature := base64.StdEncoding.EncodeToString([]byte(hex)) + req, err := http.NewRequest(method, path, strings.NewReader("")) + + req.Header.Add("Authorization", i.ClientKey + ":" + signature) + req.Header.Add("X-Auth-Timestamp", nonce) + req.Header.Add("X-Auth-Nonce", nonce) + req.Header.Add("Content-Type", "application/json") + + client := &http.Client{} + resp, err := client.Do(req) + + if err != nil { + return errors.New("SendAuthenticatedHTTPRequest: Unable to send request") + } + + contents, _ := ioutil.ReadAll(resp.Body) + fmt.Printf("Recieved raw: %s\n", string(contents)) + resp.Body.Close() + return nil +} \ No newline at end of file diff --git a/okcoinhttp.go b/okcoinhttp.go new file mode 100644 index 00000000..b6b39815 --- /dev/null +++ b/okcoinhttp.go @@ -0,0 +1,184 @@ +package main + +import ( + "net/http" + "net/url" + "crypto/md5" + "errors" + "strings" + "encoding/hex" + "io/ioutil" + "strconv" + "fmt" +) + +const ( + OKCOIN_API_URL = "https://www.okcoin.com/api/v1/" + OKCOIN_API_URL_CHINA = "https://www.okcoin.cn/api/v1/" +) + +type OKCoin struct { + PartnerID, SecretKey string +} + +func (o *OKCoin) GetTicker(symbol string) (bool) { + path := "ticker.do?symbol=" + symbol + err := SendHTTPRequest(OKCOIN_API_URL + path, true, nil) + + if err != nil { + fmt.Println(err) + return false + } + return true +} + +func (o *OKCoin) GetOrderBook(symbol string) (bool) { + path := "depth.do?symbol=" + symbol + err := SendHTTPRequest(OKCOIN_API_URL + path, true, nil) + if err != nil { + fmt.Println(err) + return false + } + return true +} + +func (o *OKCoin) GetTradeHistory(symbol string) (bool) { + path := "trades.do?symbol=" + symbol + err := SendHTTPRequest(OKCOIN_API_URL + path, true, nil) + if err != nil { + fmt.Println(err) + return false + } + return true +} + +func (o *OKCoin) GetUserInfo() { + v := url.Values{} + v.Set("partner", o.PartnerID) + err := o.SendAuthenticatedHTTPRequest("userinfo.do", v) + + if err != nil { + fmt.Println(err) + } +} + +func (o *OKCoin) Trade(amount, price float64, symbol, orderType string) { + v := url.Values{} + v.Set("partner", o.PartnerID) + v.Set("amount", strconv.FormatFloat(amount, 'f', 8, 64)) + v.Set("price", strconv.FormatFloat(price, 'f', 8, 64)) + v.Set("symbol", symbol) + v.Set("type", orderType) + + err := o.SendAuthenticatedHTTPRequest("trade.do", v) + + if err != nil { + fmt.Println(err) + } +} + +func (o *OKCoin) BatchTrade(orderData string, symbol, orderType string) { + v := url.Values{} //to-do batch trade support for orders_data + v.Set("partner", o.PartnerID) + v.Set("orders_data", orderData) + v.Set("symbol", symbol) + v.Set("type", orderType) + + err := o.SendAuthenticatedHTTPRequest("batch_trade.do", v) + + if err != nil { + fmt.Println(err) + } +} + +func (o *OKCoin) CancelOrder(orderID int64, symbol string) { + v := url.Values{} + v.Set("partner", o.PartnerID) + v.Set("orders_id", strconv.FormatInt(orderID, 10)) + v.Set("symbol", symbol) + + err := o.SendAuthenticatedHTTPRequest("cancel_order.do", v) + + if err != nil { + fmt.Println(err) + } +} + +func (o *OKCoin) GetOrderInfo(orderID int64, symbol string) { + v := url.Values{} + v.Set("partner", o.PartnerID) + v.Set("orders_id", strconv.FormatInt(orderID, 10)) + v.Set("symbol", symbol) + + err := o.SendAuthenticatedHTTPRequest("order_info.do", v) + + if err != nil { + fmt.Println(err) + } +} + +func (o *OKCoin) GetOrdersInfo(orderID int64, orderType string, symbol string) { + v := url.Values{} + v.Set("partner", o.PartnerID) + v.Set("orders_id", strconv.FormatInt(orderID, 10)) + v.Set("type", orderType) + v.Set("symbol", symbol) + + err := o.SendAuthenticatedHTTPRequest("orders_info.do", v) + + if err != nil { + fmt.Println(err) + } +} + +func (o *OKCoin) GetOrderHistory(orderID, pageLength, currentPage int64, orderType string, status, symbol string) { + v := url.Values{} + v.Set("partner", o.PartnerID) + v.Set("orders_id", strconv.FormatInt(orderID, 10)) + v.Set("type", orderType) + v.Set("symbol", symbol) + v.Set("status", status) + v.Set("current_page", strconv.FormatInt(currentPage, 10)) + v.Set("page_length", strconv.FormatInt(pageLength, 10)) + + err := o.SendAuthenticatedHTTPRequest("orders_info.do", v) + + if err != nil { + fmt.Println(err) + } +} + +func (o *OKCoin) SendAuthenticatedHTTPRequest(method string, v url.Values) (err error) { + hasher := md5.New() + hasher.Write([]byte(v.Encode() + "&secret_key=" + o.SecretKey)) + signature := strings.ToUpper(hex.EncodeToString(hasher.Sum(nil))) + + v.Set("sign", signature) + encoded := v.Encode() + "&partner=" + o.PartnerID + + fmt.Printf("Signature: %s\n", signature) + path := OKCOIN_API_URL + method + fmt.Printf("Sending POST request to %s with params %s\n", path, encoded) + + reqBody := strings.NewReader(encoded) + req, err := http.NewRequest("POST", path, reqBody) + + if err != nil { + return err + } + + req.Header.Add("Content-Type", "application/x-www-form-urlencoded") + + client := &http.Client{} + resp, err := client.Do(req) + + if err != nil { + return errors.New("PostRequest: Unable to send request") + } + + contents, _ := ioutil.ReadAll(resp.Body) + fmt.Printf("Recieved raw: %s\n", string(contents)) + resp.Body.Close() + return nil + +} \ No newline at end of file