Skip to content

Commit

Permalink
Added basic HTTP API support for Poloniex.
Browse files Browse the repository at this point in the history
  • Loading branch information
thrasher- committed Feb 10, 2016
1 parent 9c86745 commit 0353816
Show file tree
Hide file tree
Showing 5 changed files with 314 additions and 5 deletions.
11 changes: 6 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,13 @@ A cryptocurrency trading bot supporting multiple exchanges written in Golang.
| BTCMarkets | Yes | NA | NA |
| Coinbase | Yes | Yes | No|
| Gemini | Yes | NA | NA |
| Huobi | Yes | Yes |No
| Huobi | Yes | Yes |No |
| ItBit | Yes | NA | NA |
| Kraken | Yes | NA | NA
| LakeBTC | Yes | Yes | NA
| LocalBitcoins | No | NA | NA
|OKCoin (both) | Yes | Yes | No
| Kraken | Yes | NA | NA |
| LakeBTC | Yes | Yes | NA |
| LocalBitcoins | No | NA | NA |
| OKCoin (both) | Yes | Yes | No |
| Poloniex | Yes | No | NA |

** NA means not applicable as the Exchange does not support the feature.

Expand Down
13 changes: 13 additions & 0 deletions config_example.json
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,19 @@
"AvailablePairs": "BTCUSD,LTCUSD",
"EnabledPairs": "BTCUSD,LTCUSD",
"BaseCurrencies": "USD"
},
{
"Name": "Poloniex",
"Enabled": true,
"Verbose": false,
"Websocket": false,
"RESTPollingDelay": 10,
"AuthenticatedAPISupport": false,
"APIKey": "Key",
"APISecret": "Secret",
"AvailablePairs": "BTC_XUSD,BTC_FCT,BTC_MMNXT,BTC_NMC,BTC_BITUSD,BTC_RDD,BTC_XMR,BTC_XST,BTC_DSH,BTC_MAID,BTC_DGB,BTC_NEOS,BTC_BLK,BTC_NAUT,BTC_NBT,BTC_XCP,BTC_STR,BTC_BTCD,BTC_GRC,BTC_HUC,BTC_BBR,BTC_XDN,BTC_INDEX,BTC_IOC,BTC_SWARM,BTC_EMC2,BTC_MCN,BTC_NOXT,BTC_MINT,BTC_PTS,BTC_SC,BTC_GEO,BTC_XRP,BTC_FLO,BTC_BITS,BTC_HYP,BTC_XCR,BTC_LTBC,BTC_SYS,BTC_GMC,BTC_ETH,BTC_SYNC,BTC_GAP,BTC_BCN,BTC_C2,BTC_PINK,BTC_FIBRE,BTC_POT,BTC_QTL,BTC_SDC,BTC_XC,BTC_DASH,BTC_SILK,BTC_CLAM,BTC_NAV,BTC_PIGGY,BTC_BCY,BTC_MIL,BTC_XCN,BTC_YACC,BTC_BTS,BTC_QBK,BTC_SJCX,BTC_LQD,BTC_BURST,BTC_RIC,BTC_VRC,BTC_LTC,BTC_XPB,BTC_GRS,BTC_XCH,BTC_ARCH,BTC_QORA,BTC_HZ,BTC_NSR,BTC_XPM,BTC_BITCNY,BTC_EXE,BTC_XMG,BTC_BTC,BTC_BTM,BTC_NOBL,BTC_NXT,BTC_DOGE,BTC_CURE,BTC_MNTA,BTC_ADN,BTC_EXP,BTC_VTC,BTC_FLDC,BTC_MRS,BTC_MYR,BTC_OMNI,BTC_VNL,BTC_USDT,BTC_NOTE,BTC_WDC,BTC_BELA,BTC_VIA,BTC_CGA,BTC_DIEM,BTC_IFC,BTC_XDP,BTC_BLOCK,BTC_MMC,BTC_1CR,BTC_UNITY,BTC_XBC,BTC_GEMZ,BTC_FLT,BTC_PPC,BTC_XEM,BTC_RBY,BTC_CNMT,BTC_ABY,XMR_XDN,XMR_IFC,XMR_DIEM,XMR_BBR,XMR_DSH,XMR_BCN,XMR_LTC,XMR_MAID,XMR_DASH,XMR_BTCD,XMR_HYP,XMR_BLK,XMR_QORA,XMR_MNTA,XMR_NXT,USDT_BTC,USDT_ETH,USDT_XRP,USDT_DASH,USDT_LTC,USDT_NXT,USDT_XMR,USDT_STR",
"EnabledPairs": "BTC_LTC,BTC_ETH,BTC_DOGE,BTC_DASH,BTC_XRP",
"BaseCurrencies": "USD"
}
]
}
8 changes: 8 additions & 0 deletions events.go
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,13 @@ func (e *Event) CheckCondition() bool {
lastPrice = bot.exchange.anx.GetTicker("BTCUSD").Data.Last.Value
} else if bot.exchange.kraken.GetName() == e.Exchange {
lastPrice = bot.exchange.kraken.Ticker["XBTUSD"].Last
} else if bot.exchange.poloniex.GetName() == e.Exchange {
result, err := bot.exchange.poloniex.GetTicker()
if err != nil {
lastPrice = 0
} else {
lastPrice = result["BTC_LTC"].Last
}
}

if lastPrice == 0 {
Expand Down Expand Up @@ -284,6 +291,7 @@ func IsValidExchange(Exchange string) bool {
bot.exchange.localbitcoins.GetName() == Exchange && bot.exchange.localbitcoins.IsEnabled() ||
bot.exchange.okcoinChina.GetName() == Exchange && bot.exchange.okcoinChina.IsEnabled() ||
bot.exchange.okcoinIntl.GetName() == Exchange && bot.exchange.okcoinIntl.IsEnabled() ||
bot.exchange.poloniex.GetName() == Exchange && bot.exchange.poloniex.IsEnabled() ||
bot.exchange.anx.GetName() == Exchange && bot.exchange.anx.IsEnabled() {
return true
}
Expand Down
16 changes: 16 additions & 0 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ type Exchange struct {
itbit ItBit
lakebtc LakeBTC
localbitcoins LocalBitcoins
poloniex Poloniex
huobi HUOBI
kraken Kraken
}
Expand Down Expand Up @@ -110,6 +111,7 @@ func main() {
bot.exchange.itbit.SetDefaults()
bot.exchange.lakebtc.SetDefaults()
bot.exchange.localbitcoins.SetDefaults()
bot.exchange.poloniex.SetDefaults()
bot.exchange.huobi.SetDefaults()

err = RetrieveConfigCurrencyPairs(bot.config)
Expand Down Expand Up @@ -335,6 +337,20 @@ func main() {
bot.exchange.localbitcoins.EnabledPairs = SplitStrings(exch.EnabledPairs, ",")
go bot.exchange.localbitcoins.Run()
}
} else if bot.exchange.poloniex.GetName() == exch.Name {
if !exch.Enabled {
bot.exchange.poloniex.SetEnabled(false)
} else {
bot.exchange.poloniex.AuthenticatedAPISupport = exch.AuthenticatedAPISupport
bot.exchange.poloniex.SetAPIKeys(exch.APIKey, exch.APISecret)
bot.exchange.poloniex.RESTPollingDelay = exch.RESTPollingDelay
bot.exchange.poloniex.Verbose = exch.Verbose
bot.exchange.poloniex.Websocket = exch.Websocket
bot.exchange.poloniex.BaseCurrencies = SplitStrings(exch.BaseCurrencies, ",")
bot.exchange.poloniex.AvailablePairs = SplitStrings(exch.AvailablePairs, ",")
bot.exchange.poloniex.EnabledPairs = SplitStrings(exch.EnabledPairs, ",")
go bot.exchange.poloniex.Run()
}
} else if bot.exchange.huobi.GetName() == exch.Name {
if !exch.Enabled {
bot.exchange.huobi.SetEnabled(false)
Expand Down
271 changes: 271 additions & 0 deletions poloniexhttp.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,271 @@
package main

import (
"fmt"
"log"
"net/url"
"strconv"
"time"
)

const (
POLONIEX_API_URL = "https://poloniex.com"
POLONIEX_WEBSOCKET_ADDRESS = "wss://api.poloniex.com"
POLONIEX_API_VERSION = "1"
)

type Poloniex struct {
Name string
Enabled bool
Verbose bool
Websocket bool
RESTPollingDelay time.Duration
AuthenticatedAPISupport bool
AccessKey, SecretKey string
Fee float64
BaseCurrencies []string
AvailablePairs []string
EnabledPairs []string
}

type PoloniexTicker struct {
Last float64 `json:"last,string"`
LowestAsk float64 `json:"lowestAsk,string"`
HighestBid float64 `json:"highestBid,string"`
PercentChange float64 `json:"percentChange,string"`
BaseVolume float64 `json:"baseVolume,string"`
QuoteVolume float64 `json:"quoteVolume,string"`
IsFrozen int `json:"isFrozen,string"`
High24Hr float64 `json:"high24hr,string"`
Low24Hr float64 `json:"low24hr,string"`
}

func (p *Poloniex) SetDefaults() {
p.Name = "Poloniex"
p.Enabled = true
p.Fee = 0
p.Verbose = false
p.Websocket = false
p.RESTPollingDelay = 10
}

func (p *Poloniex) GetName() string {
return p.Name
}

func (p *Poloniex) SetEnabled(enabled bool) {
p.Enabled = enabled
}

func (p *Poloniex) IsEnabled() bool {
return p.Enabled
}

func (p *Poloniex) SetAPIKeys(apiKey, apiSecret string) {
p.AccessKey = apiKey
p.SecretKey = apiSecret
}

func (p *Poloniex) GetFee() float64 {
return p.Fee
}

func (p *Poloniex) Run() {
if p.Verbose {
log.Printf("%s Websocket: %s (url: %s).\n", p.GetName(), IsEnabled(p.Websocket), POLONIEX_WEBSOCKET_ADDRESS)
log.Printf("%s polling delay: %ds.\n", p.GetName(), p.RESTPollingDelay)
log.Printf("%s %d currencies enabled: %s.\n", p.GetName(), len(p.EnabledPairs), p.EnabledPairs)
}

if p.Websocket {
//go p.WebsocketClient()
}

for p.Enabled {
for _, x := range p.EnabledPairs {
currency := x
go func() {
ticker, err := p.GetTicker()
if err != nil {
log.Println(err)
return
}
log.Printf("Poloniex %s Last %f High %f Low %f Volume %f\n", currency, ticker[currency].Last, ticker[currency].High24Hr, ticker[currency].Low24Hr, ticker[currency].QuoteVolume)
//AddExchangeInfo(p.GetName(), currency[0:3], currency[3:], ticker.Last, ticker.Volume)
}()
}
time.Sleep(time.Second * p.RESTPollingDelay)
}
}

func (p *Poloniex) GetTicker() (map[string]PoloniexTicker, error) {
type response struct {
Data map[string]PoloniexTicker
}

resp := response{}
path := fmt.Sprintf("%s/public?command=returnTicker", POLONIEX_API_URL)
err := SendHTTPGetRequest(path, true, &resp.Data)

if err != nil {
return resp.Data, err
}
return resp.Data, nil
}

func (p *Poloniex) GetVolume() (interface{}, error) {
var resp interface{}
path := fmt.Sprintf("%s/public?command=return24hVolume", POLONIEX_API_URL)
err := SendHTTPGetRequest(path, true, &resp)

if err != nil {
return resp, err
}
return resp, nil
}

type PoloniexOrderbook struct {
Asks [][]interface{} `json:"asks"`
Bids [][]interface{} `json:"bids"`
IsFrozen string `json:"isFrozen"`
}

//TO-DO: add support for individual pair depth fetching
func (p *Poloniex) GetOrderbook(currencyPair string, depth int) (map[string]PoloniexOrderbook, error) {
type Response struct {
Data map[string]PoloniexOrderbook
}

vals := url.Values{}
vals.Set("currencyPair", currencyPair)

if depth != 0 {
vals.Set("depth", strconv.Itoa(depth))
}

resp := Response{}
path := fmt.Sprintf("%s/public?command=returnOrderBook&%s", POLONIEX_API_URL, vals.Encode())
err := SendHTTPGetRequest(path, true, &resp.Data)

if err != nil {
return resp.Data, err
}
return resp.Data, nil
}

type PoloniexTradeHistory struct {
GlobalTradeID int64 `json:"globalTradeID"`
TradeID int64 `json:"tradeID"`
Date string `json:"date"`
Type string `json:"type"`
Rate float64 `json:"rate,string"`
Amount float64 `json:"amount,string"`
Total float64 `json:"total,string"`
}

func (p *Poloniex) GetTradeHistory(currencyPair, start, end string) ([]PoloniexTradeHistory, error) {
vals := url.Values{}
vals.Set("currencyPair", currencyPair)

if start != "" {
vals.Set("start", start)
}

if end != "" {
vals.Set("end", end)
}

resp := []PoloniexTradeHistory{}
path := fmt.Sprintf("%s/public?command=returnTradeHistory&%s", POLONIEX_API_URL, vals.Encode())
err := SendHTTPGetRequest(path, true, &resp)

if err != nil {
return nil, err
}
return resp, nil
}

type PoloniexChartData struct {
Date int `json:"date"`
High float64 `json:"high"`
Low float64 `json:"low"`
Open float64 `json:"open"`
Close float64 `json:"close"`
Volume float64 `json:"volume"`
QuoteVolume float64 `json:"quoteVolume"`
WeightedAverage float64 `json:"weightedAverage"`
}

func (p *Poloniex) GetChartData(currencyPair, start, end, period string) ([]PoloniexChartData, error) {
vals := url.Values{}
vals.Set("currencyPair", currencyPair)

if start != "" {
vals.Set("start", start)
}

if end != "" {
vals.Set("end", end)
}

if period != "" {
vals.Set("period", period)
}

resp := []PoloniexChartData{}
path := fmt.Sprintf("%s/public?command=returnChartData&%s", POLONIEX_API_URL, vals.Encode())
err := SendHTTPGetRequest(path, true, &resp)

if err != nil {
return nil, err
}
return resp, nil
}

type PoloniexCurrencies struct {
Name string `json:"name"`
MaxDailyWithdrawal string `json:"maxDailyWithdrawal"`
TxFee float64 `json:"txFee,string"`
MinConfirmations int `json:"minConf"`
DepositAddresses interface{} `json:"depositAddress"`
Disabled int `json:"disabled"`
Delisted int `json:"delisted"`
Frozen int `json:"frozen"`
}

func (p *Poloniex) GetCurrencies() (map[string]PoloniexCurrencies, error) {
type Response struct {
Data map[string]PoloniexCurrencies
}
resp := Response{}
path := fmt.Sprintf("%s/public?command=returnCurrencies", POLONIEX_API_URL)
err := SendHTTPGetRequest(path, true, &resp.Data)

if err != nil {
return resp.Data, err
}
return resp.Data, nil
}

type PoloniexLoanOrder struct {
Rate float64 `json:"rate,string"`
Amount float64 `json:"amount,string"`
RangeMin int `json:"rangeMin"`
RangeMax int `json:"rangeMax"`
}

type PoloniexLoanOrders struct {
Offers []PoloniexLoanOrder `json:"offers"`
Demands []PoloniexLoanOrder `json:"demands"`
}

func (p *Poloniex) GetLoanOrders(currency string) (PoloniexLoanOrders, error) {
resp := PoloniexLoanOrders{}
path := fmt.Sprintf("%s/public?command=returnLoanOrders&currency=%s", POLONIEX_API_URL, currency)
err := SendHTTPGetRequest(path, true, &resp)

if err != nil {
return resp, err
}
return resp, nil
}

0 comments on commit 0353816

Please sign in to comment.