package main import ( "errors" "fmt" "log" "net/url" "strconv" "strings" "time" ) const ( KRAKEN_API_URL = "https://api.kraken.com" KRAKEN_API_VERSION = "0" KRAKEN_SERVER_TIME = "Time" KRAKEN_ASSETS = "Assets" KRAKEN_ASSET_PAIRS = "AssetPairs" KRAKEN_TICKER = "Ticker" KRAKEN_OHLC = "OHLC" KRAKEN_DEPTH = "Depth" KRAKEN_TRADES = "Trades" KRAKEN_SPREAD = "Spread" KRAKEN_BALANCE = "Balance" KRAKEN_TRADE_BALANCE = "TradeBalance" KRAKEN_OPEN_ORDERS = "OpenOrders" KRAKEN_CLOSED_ORDERS = "ClosedOrders" KRAKEN_QUERY_ORDERS = "QueryOrders" KRAKEN_TRADES_HISTORY = "TradesHistory" KRAKEN_QUERY_TRADES = "QueryTrades" KRAKEN_OPEN_POSITIONS = "OpenPositions" KRAKEN_LEDGERS = "Ledgers" KRAKEN_QUERY_LEDGERS = "QueryLedgers" KRAKEN_TRADE_VOLUME = "TradeVolume" KRAKEN_ORDER_CANCEL = "CancelOrder" KRAKEN_ORDER_PLACE = "AddOrder" ) type Kraken struct { Name string Enabled bool Verbose bool Websocket bool RESTPollingDelay time.Duration AuthenticatedAPISupport bool ClientKey, APISecret string FiatFee, CryptoFee float64 BaseCurrencies []string AvailablePairs []string EnabledPairs []string Ticker map[string]KrakenTicker } func (k *Kraken) SetDefaults() { k.Name = "Kraken" k.Enabled = false k.FiatFee = 0.35 k.CryptoFee = 0.10 k.Verbose = false k.Websocket = false k.RESTPollingDelay = 10 k.Ticker = make(map[string]KrakenTicker) } func (k *Kraken) GetName() string { return k.Name } func (k *Kraken) SetEnabled(enabled bool) { k.Enabled = enabled } func (k *Kraken) IsEnabled() bool { return k.Enabled } func (k *Kraken) Setup(exch Exchanges) { if !exch.Enabled { k.SetEnabled(false) } else { k.Enabled = true k.AuthenticatedAPISupport = exch.AuthenticatedAPISupport k.SetAPIKeys(exch.APIKey, exch.APISecret) k.RESTPollingDelay = exch.RESTPollingDelay k.Verbose = exch.Verbose k.Websocket = exch.Websocket k.BaseCurrencies = SplitStrings(exch.BaseCurrencies, ",") k.AvailablePairs = SplitStrings(exch.AvailablePairs, ",") k.EnabledPairs = SplitStrings(exch.EnabledPairs, ",") } } func (k *Kraken) GetEnabledCurrencies() []string { return k.EnabledPairs } func (k *Kraken) Start() { go k.Run() } func (k *Kraken) SetAPIKeys(apiKey, apiSecret string) { k.ClientKey = apiKey k.APISecret = apiSecret } func (k *Kraken) GetFee(cryptoTrade bool) float64 { if cryptoTrade { return k.CryptoFee } else { return k.FiatFee } } func (k *Kraken) Run() { if k.Verbose { log.Printf("%s polling delay: %ds.\n", k.GetName(), k.RESTPollingDelay) log.Printf("%s %d currencies enabled: %s.\n", k.GetName(), len(k.EnabledPairs), k.EnabledPairs) } for k.Enabled { err := k.GetTicker(JoinStrings(k.EnabledPairs, ",")) if err != nil { log.Println(err) } else { for _, x := range k.EnabledPairs { ticker := k.Ticker[x] log.Printf("Kraken %s Last %f High %f Low %f Volume %f\n", x, ticker.Last, ticker.High, ticker.Low, ticker.Volume) AddExchangeInfo(k.GetName(), x[0:3], x[3:], ticker.Last, ticker.Volume) } } time.Sleep(time.Second * k.RESTPollingDelay) } } func (k *Kraken) GetServerTime() error { var result interface{} path := fmt.Sprintf("%s/%s/public/%s", KRAKEN_API_URL, KRAKEN_API_VERSION, KRAKEN_SERVER_TIME) err := SendHTTPGetRequest(path, true, &result) if err != nil { return err } log.Println(result) return nil } func (k *Kraken) GetAssets() error { var result interface{} path := fmt.Sprintf("%s/%s/public/%s", KRAKEN_API_URL, KRAKEN_API_VERSION, KRAKEN_ASSETS) err := SendHTTPGetRequest(path, true, &result) if err != nil { return err } log.Println(result) return nil } func (k *Kraken) GetAssetPairs() error { var result interface{} path := fmt.Sprintf("%s/%s/public/%s", KRAKEN_API_URL, KRAKEN_API_VERSION, KRAKEN_ASSET_PAIRS) err := SendHTTPGetRequest(path, true, &result) if err != nil { return err } log.Println(result) return nil } type KrakenTicker struct { Ask float64 Bid float64 Last float64 Volume float64 VWAP float64 Trades int64 Low float64 High float64 Open float64 } type KrakenTickerResponse struct { Ask []string `json:"a"` Bid []string `json:"b"` Last []string `json:"c"` Volume []string `json:"v"` VWAP []string `json:"p"` Trades []int64 `json:"t"` Low []string `json:"l"` High []string `json:"h"` Open string `json:"o"` } func (k *Kraken) GetTicker(symbol string) error { values := url.Values{} values.Set("pair", symbol) type Response struct { Error []interface{} `json:"error"` Data map[string]KrakenTickerResponse `json:"result"` } resp := Response{} path := fmt.Sprintf("%s/%s/public/%s?%s", KRAKEN_API_URL, KRAKEN_API_VERSION, KRAKEN_TICKER, values.Encode()) err := SendHTTPGetRequest(path, true, &resp) if err != nil { return err } if len(resp.Error) > 0 { return errors.New(fmt.Sprintf("Kraken error: %s", resp.Error)) } for x, y := range resp.Data { x = x[1:4] + x[5:] ticker := KrakenTicker{} ticker.Ask, _ = strconv.ParseFloat(y.Ask[0], 64) ticker.Bid, _ = strconv.ParseFloat(y.Bid[0], 64) ticker.Last, _ = strconv.ParseFloat(y.Last[0], 64) ticker.Volume, _ = strconv.ParseFloat(y.Volume[1], 64) ticker.VWAP, _ = strconv.ParseFloat(y.VWAP[1], 64) ticker.Trades = y.Trades[1] ticker.Low, _ = strconv.ParseFloat(y.Low[1], 64) ticker.High, _ = strconv.ParseFloat(y.High[1], 64) ticker.Open, _ = strconv.ParseFloat(y.Open, 64) k.Ticker[x] = ticker } return nil } //This will return the TickerPrice struct when tickers are completed here.. func (k *Kraken) GetTickerPrice(currency string) TickerPrice { var tickerPrice TickerPrice /* ticker, err := i.GetTicker(currency) if err != nil { log.Println(err) return tickerPrice } tickerPrice.Ask = ticker.Ask tickerPrice.Bid = ticker.Bid */ return tickerPrice } func (k *Kraken) GetOHLC(symbol string) error { values := url.Values{} values.Set("pair", symbol) var result interface{} path := fmt.Sprintf("%s/%s/public/%s?%s", KRAKEN_API_URL, KRAKEN_API_VERSION, KRAKEN_OHLC, values.Encode()) err := SendHTTPGetRequest(path, true, &result) if err != nil { return err } log.Println(result) return nil } func (k *Kraken) GetDepth(symbol string) error { values := url.Values{} values.Set("pair", symbol) var result interface{} path := fmt.Sprintf("%s/%s/public/%s?%s", KRAKEN_API_URL, KRAKEN_API_VERSION, KRAKEN_DEPTH, values.Encode()) err := SendHTTPGetRequest(path, true, &result) if err != nil { return err } log.Println(result) return nil } func (k *Kraken) GetTrades(symbol string) error { values := url.Values{} values.Set("pair", symbol) var result interface{} path := fmt.Sprintf("%s/%s/public/%s?%s", KRAKEN_API_URL, KRAKEN_API_VERSION, KRAKEN_TRADES, values.Encode()) err := SendHTTPGetRequest(path, true, &result) if err != nil { return err } log.Println(result) return nil } func (k *Kraken) GetSpread(symbol string) { values := url.Values{} values.Set("pair", symbol) var result interface{} path := fmt.Sprintf("%s/%s/public/%s?%s", KRAKEN_API_URL, KRAKEN_API_VERSION, KRAKEN_SPREAD, values.Encode()) err := SendHTTPGetRequest(path, true, &result) if err != nil { log.Println(err) return } } func (k *Kraken) GetBalance() { result, err := k.SendAuthenticatedHTTPRequest(KRAKEN_BALANCE, url.Values{}) if err != nil { log.Println(err) return } log.Println(result) } func (k *Kraken) GetTradeBalance(symbol, asset string) { values := url.Values{} if len(symbol) > 0 { values.Set("aclass", symbol) } if len(asset) > 0 { values.Set("asset", asset) } result, err := k.SendAuthenticatedHTTPRequest(KRAKEN_TRADE_BALANCE, values) if err != nil { log.Println(err) return } log.Println(result) } func (k *Kraken) GetOpenOrders(showTrades bool, userref int64) { values := url.Values{} if showTrades { values.Set("trades", "true") } if userref != 0 { values.Set("userref", strconv.FormatInt(userref, 10)) } result, err := k.SendAuthenticatedHTTPRequest(KRAKEN_OPEN_ORDERS, values) if err != nil { log.Println(err) return } log.Println(result) } func (k *Kraken) GetClosedOrders(showTrades bool, userref, start, end, offset int64, closetime string) { values := url.Values{} if showTrades { values.Set("trades", "true") } if userref != 0 { values.Set("userref", strconv.FormatInt(userref, 10)) } if start != 0 { values.Set("start", strconv.FormatInt(start, 10)) } if end != 0 { values.Set("end", strconv.FormatInt(end, 10)) } if offset != 0 { values.Set("ofs", strconv.FormatInt(offset, 10)) } if len(closetime) > 0 { values.Set("closetime", closetime) } result, err := k.SendAuthenticatedHTTPRequest(KRAKEN_CLOSED_ORDERS, values) if err != nil { log.Println(err) return } log.Println(result) } func (k *Kraken) QueryOrdersInfo(showTrades bool, userref, txid int64) { values := url.Values{} if showTrades { values.Set("trades", "true") } if userref != 0 { values.Set("userref", strconv.FormatInt(userref, 10)) } if txid != 0 { values.Set("txid", strconv.FormatInt(userref, 10)) } result, err := k.SendAuthenticatedHTTPRequest(KRAKEN_QUERY_ORDERS, values) if err != nil { log.Println(err) return } log.Println(result) } func (k *Kraken) GetTradesHistory(tradeType string, showRelatedTrades bool, start, end, offset int64) { values := url.Values{} if len(tradeType) > 0 { values.Set("aclass", tradeType) } if showRelatedTrades { values.Set("trades", "true") } if start != 0 { values.Set("start", strconv.FormatInt(start, 10)) } if end != 0 { values.Set("end", strconv.FormatInt(end, 10)) } if offset != 0 { values.Set("offset", strconv.FormatInt(offset, 10)) } result, err := k.SendAuthenticatedHTTPRequest(KRAKEN_TRADES_HISTORY, values) if err != nil { log.Println(err) return } log.Println(result) } func (k *Kraken) QueryTrades(txid int64, showRelatedTrades bool) { values := url.Values{} values.Set("txid", strconv.FormatInt(txid, 10)) if showRelatedTrades { values.Set("trades", "true") } result, err := k.SendAuthenticatedHTTPRequest(KRAKEN_QUERY_TRADES, values) if err != nil { log.Println(err) return } log.Println(result) } func (k *Kraken) OpenPositions(txid int64, showPL bool) { values := url.Values{} values.Set("txid", strconv.FormatInt(txid, 10)) if showPL { values.Set("docalcs", "true") } result, err := k.SendAuthenticatedHTTPRequest(KRAKEN_OPEN_POSITIONS, values) if err != nil { log.Println(err) return } log.Println(result) } func (k *Kraken) GetLedgers(symbol, asset, ledgerType string, start, end, offset int64) { values := url.Values{} if len(symbol) > 0 { values.Set("aclass", symbol) } if len(asset) > 0 { values.Set("asset", asset) } if len(ledgerType) > 0 { values.Set("type", ledgerType) } if start != 0 { values.Set("start", strconv.FormatInt(start, 10)) } if end != 0 { values.Set("end", strconv.FormatInt(end, 10)) } if offset != 0 { values.Set("offset", strconv.FormatInt(offset, 10)) } result, err := k.SendAuthenticatedHTTPRequest(KRAKEN_LEDGERS, values) if err != nil { log.Println(err) return } log.Println(result) } func (k *Kraken) QueryLedgers(id string) { values := url.Values{} values.Set("id", id) result, err := k.SendAuthenticatedHTTPRequest(KRAKEN_QUERY_LEDGERS, values) if err != nil { log.Println(err) return } log.Println(result) } func (k *Kraken) GetTradeVolume(symbol string) { values := url.Values{} values.Set("pair", symbol) result, err := k.SendAuthenticatedHTTPRequest(KRAKEN_TRADE_VOLUME, values) if err != nil { log.Println(err) return } log.Println(result) } func (k *Kraken) AddOrder(symbol, side, orderType string, price, price2, volume, leverage, position float64) { values := url.Values{} values.Set("pairs", symbol) values.Set("type", side) values.Set("ordertype", orderType) values.Set("price", strconv.FormatFloat(price, 'f', -1, 64)) values.Set("price2", strconv.FormatFloat(price, 'f', -1, 64)) values.Set("volume", strconv.FormatFloat(volume, 'f', -1, 64)) values.Set("leverage", strconv.FormatFloat(leverage, 'f', -1, 64)) values.Set("position", strconv.FormatFloat(position, 'f', -1, 64)) result, err := k.SendAuthenticatedHTTPRequest(KRAKEN_ORDER_PLACE, values) if err != nil { log.Println(err) return } log.Println(result) } func (k *Kraken) CancelOrder(orderID int64) { values := url.Values{} values.Set("txid", strconv.FormatInt(orderID, 10)) result, err := k.SendAuthenticatedHTTPRequest(KRAKEN_ORDER_CANCEL, values) if err != nil { log.Println(err) return } log.Println(result) } func (k *Kraken) SendAuthenticatedHTTPRequest(method string, values url.Values) (interface{}, error) { path := fmt.Sprintf("/%s/private/%s", KRAKEN_API_VERSION, method) values.Set("nonce", strconv.FormatInt(time.Now().UnixNano(), 10)) secret, err := Base64Decode(k.APISecret) if err != nil { return nil, err } shasum := GetSHA256([]byte(values.Get("nonce") + values.Encode())) signature := Base64Encode(GetHMAC(HASH_SHA512, append([]byte(path), shasum...), secret)) if k.Verbose { log.Printf("Sending POST request to %s, path: %s.", KRAKEN_API_URL, path) } headers := make(map[string]string) headers["API-Key"] = k.ClientKey headers["API-Sign"] = signature resp, err := SendHTTPRequest("POST", KRAKEN_API_URL+path, headers, strings.NewReader(values.Encode())) if err != nil { return nil, err } if k.Verbose { log.Printf("Recieved raw: \n%s\n", resp) } return resp, nil }