mirror of
https://github.com/d0zingcat/gocryptotrader.git
synced 2026-05-13 23:16:45 +00:00
Added basic LocalBitcoins support.
This commit is contained in:
@@ -21,6 +21,7 @@ A cryptocurrency trading bot supporting multiple exchanges written in Golang.
|
||||
| ItBit | Yes | NA | NA |
|
||||
| Kraken | Yes | NA | NA
|
||||
| LakeBTC | Yes | Yes | NA
|
||||
| LocalBitcoins | No | NA | NA
|
||||
|OKCoin (both) | Yes | Yes | No
|
||||
|
||||
** NA means not applicable as the Exchange does not support the feature.
|
||||
|
||||
@@ -200,6 +200,20 @@
|
||||
"EnabledPairs": "BTCUSD,BTCCNY",
|
||||
"BaseCurrencies": "USD,CNY,SEK"
|
||||
},
|
||||
{
|
||||
"Name": "LocalBitcoins",
|
||||
"Enabled": true,
|
||||
"Verbose": true,
|
||||
"Websocket": false,
|
||||
"RESTPollingDelay": 10,
|
||||
"AuthenticatedAPISupport": false,
|
||||
"APIKey": "Key",
|
||||
"APISecret": "Secret",
|
||||
"ClientID": "",
|
||||
"AvailablePairs": "BTCARS,BTCAUD,BTCBRL,BTCCAD,BTCCHF,BTCCZK,BTCDKK,BTCEUR,BTCGBP,BTCHKD,BTCILS,BTCINR,BTCMXN,BTCNOK,BTCNZD,BTCPLN,BTCRUB,BTCSEK,BTCSGD,BTCTHB,BTCUSD,BTCZAR",
|
||||
"EnabledPairs": "BTCARS,BTCAUD,BTCBRL,BTCCAD,BTCCHF,BTCCZK,BTCDKK,BTCEUR,BTCGBP,BTCHKD,BTCILS,BTCINR,BTCMXN,BTCNOK,BTCNZD,BTCPLN,BTCRUB,BTCSEK,BTCSGD,BTCTHB,BTCUSD,BTCZAR",
|
||||
"BaseCurrencies": "ARS,AUD,BRL,CAD,CHF,CZK,DKK,EUR,GBP,HKD,ILS,INR,MXN,NOK,NZD,PLN,RUB,SEK,SGD,THB,USD,ZAR"
|
||||
},
|
||||
{
|
||||
"Name": "OKCOIN China",
|
||||
"Enabled": true,
|
||||
|
||||
@@ -147,6 +147,13 @@ func (e *Event) CheckCondition() bool {
|
||||
}
|
||||
} else if bot.exchange.lakebtc.GetName() == e.Exchange {
|
||||
lastPrice = bot.exchange.lakebtc.GetTicker().CNY.Last
|
||||
} else if bot.exchange.localbitcoins.GetName() == e.Exchange {
|
||||
result, err := bot.exchange.localbitcoins.GetTicker()
|
||||
if err != nil {
|
||||
lastPrice = 0
|
||||
} else {
|
||||
lastPrice = result["USD"].Rates.Last
|
||||
}
|
||||
} else if bot.exchange.btcc.GetName() == e.Exchange {
|
||||
lastPrice = bot.exchange.btcc.GetTicker("btccny").Last
|
||||
} else if bot.exchange.huobi.GetName() == e.Exchange {
|
||||
@@ -277,6 +284,7 @@ func IsValidExchange(Exchange string) bool {
|
||||
bot.exchange.itbit.GetName() == Exchange && bot.exchange.itbit.IsEnabled() ||
|
||||
bot.exchange.kraken.GetName() == Exchange && bot.exchange.kraken.IsEnabled() ||
|
||||
bot.exchange.lakebtc.GetName() == Exchange && bot.exchange.lakebtc.IsEnabled() ||
|
||||
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.anx.GetName() == Exchange && bot.exchange.anx.IsEnabled() {
|
||||
|
||||
188
localbitcoinshttp.go
Normal file
188
localbitcoinshttp.go
Normal file
@@ -0,0 +1,188 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"log"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
LOCALBITCOINS_API_URL = "https://localbitcoins.com/"
|
||||
LOCALBITCOINS_API_TICKER = "bitcoinaverage/ticker-all-currencies/"
|
||||
LOCALBITCOINS_API_BITCOINCHARTS = "bitcoincharts/"
|
||||
)
|
||||
|
||||
type LocalBitcoins struct {
|
||||
Name string
|
||||
Enabled bool
|
||||
Verbose bool
|
||||
Websocket bool
|
||||
RESTPollingDelay time.Duration
|
||||
AuthenticatedAPISupport bool
|
||||
Password, APIKey, APISecret string
|
||||
TakerFee, MakerFee float64
|
||||
BaseCurrencies []string
|
||||
AvailablePairs []string
|
||||
EnabledPairs []string
|
||||
}
|
||||
|
||||
func (l *LocalBitcoins) SetDefaults() {
|
||||
l.Name = "LocalBitcoins"
|
||||
l.Enabled = true
|
||||
l.Verbose = false
|
||||
l.Verbose = false
|
||||
l.Websocket = false
|
||||
l.RESTPollingDelay = 10
|
||||
}
|
||||
|
||||
func (l *LocalBitcoins) GetName() string {
|
||||
return l.Name
|
||||
}
|
||||
|
||||
func (l *LocalBitcoins) SetEnabled(enabled bool) {
|
||||
l.Enabled = enabled
|
||||
}
|
||||
|
||||
func (l *LocalBitcoins) IsEnabled() bool {
|
||||
return l.Enabled
|
||||
}
|
||||
|
||||
func (l *LocalBitcoins) GetFee(maker bool) float64 {
|
||||
if maker {
|
||||
return l.MakerFee
|
||||
} else {
|
||||
return l.TakerFee
|
||||
}
|
||||
}
|
||||
|
||||
func (l *LocalBitcoins) Run() {
|
||||
if l.Verbose {
|
||||
log.Printf("%s polling delay: %ds.\n", l.GetName(), l.RESTPollingDelay)
|
||||
log.Printf("%s %d currencies enabled: %s.\n", l.GetName(), len(l.EnabledPairs), l.EnabledPairs)
|
||||
}
|
||||
|
||||
for l.Enabled {
|
||||
ticker, err := l.GetTicker()
|
||||
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
goto sleep
|
||||
}
|
||||
for _, x := range l.EnabledPairs {
|
||||
currency := x[3:]
|
||||
log.Printf("LocalBitcoins BTC %s: Last %f Average 1h %f Average 24h %f Volume %f\n", currency, ticker[currency].Rates.Last,
|
||||
ticker[currency].Avg1h, ticker[currency].Avg24h, ticker[currency].VolumeBTC)
|
||||
AddExchangeInfo(l.GetName(), x[0:3], x[3:], ticker[currency].Rates.Last, ticker[currency].VolumeBTC)
|
||||
}
|
||||
sleep:
|
||||
time.Sleep(time.Second * l.RESTPollingDelay)
|
||||
}
|
||||
}
|
||||
|
||||
func (l *LocalBitcoins) SetAPIKeys(apiKey, apiSecret string) {
|
||||
if !l.AuthenticatedAPISupport {
|
||||
return
|
||||
}
|
||||
|
||||
l.APIKey = apiKey
|
||||
l.APISecret = apiSecret
|
||||
}
|
||||
|
||||
type LocalBitcoinsTicker struct {
|
||||
Avg12h float64 `json:"avg_12h"`
|
||||
Avg1h float64 `json:"avg_1h"`
|
||||
Avg24h float64 `json:"avg_24h"`
|
||||
Rates struct {
|
||||
Last float64 `json:"last,string"`
|
||||
} `json:"rates"`
|
||||
VolumeBTC float64 `json:"volume_btc,string"`
|
||||
}
|
||||
|
||||
func (l *LocalBitcoins) GetTicker() (map[string]LocalBitcoinsTicker, error) {
|
||||
result := make(map[string]LocalBitcoinsTicker)
|
||||
err := SendHTTPGetRequest(LOCALBITCOINS_API_URL+LOCALBITCOINS_API_TICKER, true, &result)
|
||||
|
||||
if err != nil {
|
||||
return result, err
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
type LocalBitcoinsTrade struct {
|
||||
TID int64 `json:"tid"`
|
||||
Date int64 `json:"date"`
|
||||
Amount float64 `json:"amount,string"`
|
||||
Price float64 `json:"price,string"`
|
||||
}
|
||||
|
||||
func (l *LocalBitcoins) GetTrades(currency string, values url.Values) ([]LocalBitcoinsTrade, error) {
|
||||
path := EncodeURLValues(fmt.Sprintf("%s/%s/trades.json", LOCALBITCOINS_API_URL+LOCALBITCOINS_API_BITCOINCHARTS, currency), values)
|
||||
result := []LocalBitcoinsTrade{}
|
||||
err := SendHTTPGetRequest(path, true, &result)
|
||||
|
||||
if err != nil {
|
||||
return result, err
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
type LocalBitcoinsOrderbook struct {
|
||||
Bids []struct {
|
||||
Price float64
|
||||
Amount float64
|
||||
}
|
||||
Asks []struct {
|
||||
Price float64
|
||||
Amount float64
|
||||
}
|
||||
}
|
||||
|
||||
func (l *LocalBitcoins) GetOrderbook(currency string) (LocalBitcoinsOrderbook, error) {
|
||||
path := fmt.Sprintf("%s/%s/orderbook.json", LOCALBITCOINS_API_URL+LOCALBITCOINS_API_BITCOINCHARTS, currency)
|
||||
|
||||
type response struct {
|
||||
Bids [][]string `json:"bids"`
|
||||
Asks [][]string `json:"asks"`
|
||||
}
|
||||
|
||||
result := response{}
|
||||
err := SendHTTPGetRequest(path, true, &result)
|
||||
|
||||
if err != nil {
|
||||
return LocalBitcoinsOrderbook{}, err
|
||||
}
|
||||
|
||||
return LocalBitcoinsOrderbook{}, nil
|
||||
}
|
||||
|
||||
func (l *LocalBitcoins) SendAuthenticatedHTTPRequest(method, path string, values url.Values, result interface{}) (err error) {
|
||||
nonce := strconv.FormatInt(time.Now().UnixNano(), 10)
|
||||
payload := values.Encode()
|
||||
message := nonce + l.APIKey + path + payload
|
||||
hmac := GetHMAC(HASH_SHA256, []byte(message), []byte(l.APISecret))
|
||||
headers := make(map[string]string)
|
||||
headers["Apiauth-Key"] = l.APIKey
|
||||
headers["Apiauth-Nonce"] = nonce
|
||||
headers["Apiauth-Signature"] = StringToUpper(HexEncodeToString(hmac))
|
||||
headers["Content-Type"] = "application/x-www-form-urlencoded"
|
||||
|
||||
resp, err := SendHTTPRequest(method, LOCALBITCOINS_API_URL+"api/"+path, headers, bytes.NewBuffer([]byte(payload)))
|
||||
|
||||
if l.Verbose {
|
||||
log.Printf("Recieved raw: \n%s\n", resp)
|
||||
}
|
||||
|
||||
err = JSONDecode([]byte(resp), &result)
|
||||
|
||||
if err != nil {
|
||||
return errors.New("Unable to JSON Unmarshal response.")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
48
main.go
48
main.go
@@ -11,22 +11,23 @@ import (
|
||||
)
|
||||
|
||||
type Exchange struct {
|
||||
anx ANX
|
||||
btcc BTCC
|
||||
bitstamp Bitstamp
|
||||
bitfinex Bitfinex
|
||||
btce BTCE
|
||||
btcmarkets BTCMarkets
|
||||
coinbase Coinbase
|
||||
cryptsy Cryptsy
|
||||
dwvx DWVX
|
||||
gemini Gemini
|
||||
okcoinChina OKCoin
|
||||
okcoinIntl OKCoin
|
||||
itbit ItBit
|
||||
lakebtc LakeBTC
|
||||
huobi HUOBI
|
||||
kraken Kraken
|
||||
anx ANX
|
||||
btcc BTCC
|
||||
bitstamp Bitstamp
|
||||
bitfinex Bitfinex
|
||||
btce BTCE
|
||||
btcmarkets BTCMarkets
|
||||
coinbase Coinbase
|
||||
cryptsy Cryptsy
|
||||
dwvx DWVX
|
||||
gemini Gemini
|
||||
okcoinChina OKCoin
|
||||
okcoinIntl OKCoin
|
||||
itbit ItBit
|
||||
lakebtc LakeBTC
|
||||
localbitcoins LocalBitcoins
|
||||
huobi HUOBI
|
||||
kraken Kraken
|
||||
}
|
||||
|
||||
type Bot struct {
|
||||
@@ -89,6 +90,7 @@ func main() {
|
||||
bot.exchange.okcoinIntl.SetDefaults()
|
||||
bot.exchange.itbit.SetDefaults()
|
||||
bot.exchange.lakebtc.SetDefaults()
|
||||
bot.exchange.localbitcoins.SetDefaults()
|
||||
bot.exchange.huobi.SetDefaults()
|
||||
|
||||
err = RetrieveConfigCurrencyPairs(bot.config)
|
||||
@@ -314,6 +316,20 @@ func main() {
|
||||
bot.exchange.lakebtc.EnabledPairs = SplitStrings(exch.EnabledPairs, ",")
|
||||
go bot.exchange.lakebtc.Run()
|
||||
}
|
||||
} else if bot.exchange.localbitcoins.GetName() == exch.Name {
|
||||
if !exch.Enabled {
|
||||
bot.exchange.localbitcoins.SetEnabled(false)
|
||||
} else {
|
||||
bot.exchange.localbitcoins.AuthenticatedAPISupport = exch.AuthenticatedAPISupport
|
||||
bot.exchange.localbitcoins.SetAPIKeys(exch.APIKey, exch.APISecret)
|
||||
bot.exchange.localbitcoins.RESTPollingDelay = exch.RESTPollingDelay
|
||||
bot.exchange.localbitcoins.Verbose = exch.Verbose
|
||||
bot.exchange.localbitcoins.Websocket = exch.Websocket
|
||||
bot.exchange.localbitcoins.BaseCurrencies = SplitStrings(exch.BaseCurrencies, ",")
|
||||
bot.exchange.localbitcoins.AvailablePairs = SplitStrings(exch.AvailablePairs, ",")
|
||||
bot.exchange.localbitcoins.EnabledPairs = SplitStrings(exch.EnabledPairs, ",")
|
||||
go bot.exchange.localbitcoins.Run()
|
||||
}
|
||||
} else if bot.exchange.huobi.GetName() == exch.Name {
|
||||
if !exch.Enabled {
|
||||
bot.exchange.huobi.SetEnabled(false)
|
||||
|
||||
Reference in New Issue
Block a user