Skip to content

Commit bd21ce0

Browse files
authored
Merge pull request #42 from saniales/develop
Syncing with master
2 parents ffc46eb + 0157620 commit bd21ce0

File tree

14 files changed

+618
-233
lines changed

14 files changed

+618
-233
lines changed

.bot_config.yaml.example

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,15 @@ exchange_configs:
22
- exchange: bittrex
33
public_key: your_bittrex_public_key
44
secret_key: your_bittrex_secret_key
5+
websocket_enabled: true
56
- exchange: binance
67
public_key: your_binance_public_key
78
secret_key: your_binance_secret_key
9+
websocket_enabled: true
810
- exchange: bitfinex
911
public_key: your_bitfinex_public_key
1012
secret_key: your_bitfinex_secret_key
13+
websocket_enabled: true
1114
strategies:
1215
- strategy: your_strategy_name
1316
markets:

README.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# golang-crypto-trading-bot
22

33
[![GoDoc](https://godoc.org/github.com/saniales/golang-crypto-trading-bot?status.svg)](https://godoc.org/github.com/saniales/golang-crypto-trading-bot)
4-
[![Travis CI](https://img.shields.io/travis/saniales/golang-crypto-trading-bot.svg)]((https://github.com/saniales/golang-crypto-trading-bot))
4+
[![Travis CI](https://img.shields.io/travis/saniales/golang-crypto-trading-bot.svg)]((https://travis-ci.org/saniales/golang-crypto-trading-bot))
55
[![GitHub release](https://img.shields.io/github/release/saniales/golang-crypto-trading-bot.svg)](https://github.com/saniales/golang-crypto-trading-bot/releases)
66
[![license](https://img.shields.io/github/license/saniales/golang-crypto-trading-bot.svg?maxAge=2592000)](https://github.com/saniales/golang-crypto-trading-bot/LICENSE)
77

@@ -35,12 +35,15 @@ exchange_configs:
3535
- exchange: bittrex
3636
public_key: your_bittrex_public_key
3737
secret_key: your_bittrex_secret_key
38+
websocket_enabled: true
3839
- exchange: binance
3940
public_key: your_binance_public_key
4041
secret_key: your_binance_secret_key
42+
websocket_enabled: true
4143
- exchange: bitfinex
4244
public_key: your_bitfinex_public_key
4345
secret_key: your_bitfinex_secret_key
46+
websocket_enabled: true
4447
strategies:
4548
- strategy: your_strategy_name
4649
markets:

bot_helpers/bot_helper.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ func InitExchange(exchangeConfig environment.ExchangeConfig) exchanges.ExchangeW
1818
return exchanges.NewBinanceWrapper(exchangeConfig.PublicKey, exchangeConfig.SecretKey)
1919
case "bitfinex":
2020
return exchanges.NewBitfinexWrapper(exchangeConfig.PublicKey, exchangeConfig.SecretKey)
21+
case "hitbtc":
22+
return exchanges.NewHitBtcV2Wrapper(exchangeConfig.PublicKey, exchangeConfig.SecretKey)
2123
default:
2224
return nil
2325
}

environment/config.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,10 @@ package environment
1919
//
2020
// Can be used to generate an ExchangeWrapper.
2121
type ExchangeConfig struct {
22-
ExchangeName string `yaml:"exchange"` // Represents the exchange name.
23-
PublicKey string `yaml:"public_key"` // Represents the public key used to connect to Exchange API.
24-
SecretKey string `yaml:"secret_key"` // Represents the secret key used to connect to Exchange API.
22+
ExchangeName string `yaml:"exchange"` // Represents the exchange name.
23+
PublicKey string `yaml:"public_key"` // Represents the public key used to connect to Exchange API.
24+
SecretKey string `yaml:"secret_key"` // Represents the secret key used to connect to Exchange API.
25+
WebsocketEnabled bool `yaml:"websocket_enabled"` // Represents whether websocket communication is enabled for this exchange configuration or REST API is involved.
2526
}
2627

2728
// StrategyConfig contains where a strategy will be applied in the specified exchange.

exchanges/binance.go

Lines changed: 45 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -29,15 +29,15 @@ import (
2929
// BinanceWrapper represents the wrapper for the Binance exchange.
3030
type BinanceWrapper struct {
3131
api *binance.Client
32-
summaries SummaryCache
33-
candles CandlesCache
32+
summaries *SummaryCache
33+
candles *CandlesCache
3434
websocketOn bool
3535
}
3636

3737
// NewBinanceWrapper creates a generic wrapper of the binance API.
3838
func NewBinanceWrapper(publicKey string, secretKey string) ExchangeWrapper {
3939
client := binance.NewClient(publicKey, secretKey)
40-
return BinanceWrapper{
40+
return &BinanceWrapper{
4141
api: client,
4242
summaries: NewSummaryCache(),
4343
candles: NewCandlesCache(),
@@ -46,16 +46,16 @@ func NewBinanceWrapper(publicKey string, secretKey string) ExchangeWrapper {
4646
}
4747

4848
// Name returns the name of the wrapped exchange.
49-
func (wrapper BinanceWrapper) Name() string {
49+
func (wrapper *BinanceWrapper) Name() string {
5050
return "binance"
5151
}
5252

53-
func (wrapper BinanceWrapper) String() string {
53+
func (wrapper *BinanceWrapper) String() string {
5454
return wrapper.Name()
5555
}
5656

5757
// GetMarkets Gets all the markets info.
58-
func (wrapper BinanceWrapper) GetMarkets() ([]*environment.Market, error) {
58+
func (wrapper *BinanceWrapper) GetMarkets() ([]*environment.Market, error) {
5959
binanceMarkets, err := wrapper.api.NewListPricesService().Do(context.Background())
6060
if err != nil {
6161
return nil, err
@@ -81,7 +81,7 @@ func (wrapper BinanceWrapper) GetMarkets() ([]*environment.Market, error) {
8181
}
8282

8383
// GetOrderBook gets the order(ASK + BID) book of a market.
84-
func (wrapper BinanceWrapper) GetOrderBook(market *environment.Market) (*environment.OrderBook, error) {
84+
func (wrapper *BinanceWrapper) GetOrderBook(market *environment.Market) (*environment.OrderBook, error) {
8585
binanceOrderBook, err := wrapper.api.NewListOrdersService().Symbol(MarketNameFor(market, wrapper)).Do(context.Background())
8686
if err != nil {
8787
return nil, err
@@ -118,31 +118,31 @@ func (wrapper BinanceWrapper) GetOrderBook(market *environment.Market) (*environ
118118
}
119119

120120
// BuyLimit performs a limit buy action.
121-
func (wrapper BinanceWrapper) BuyLimit(market *environment.Market, amount float64, limit float64) (string, error) {
121+
func (wrapper *BinanceWrapper) BuyLimit(market *environment.Market, amount float64, limit float64) (string, error) {
122122
orderNumber, err := wrapper.api.NewCreateOrderService().Type(binance.OrderTypeLimit).Side(binance.SideTypeBuy).Symbol(MarketNameFor(market, wrapper)).Price(fmt.Sprint(limit)).Quantity(fmt.Sprint(amount)).Do(context.Background())
123123
return fmt.Sprint(orderNumber.ClientOrderID), err
124124
}
125125

126126
// SellLimit performs a limit sell action.
127-
func (wrapper BinanceWrapper) SellLimit(market *environment.Market, amount float64, limit float64) (string, error) {
127+
func (wrapper *BinanceWrapper) SellLimit(market *environment.Market, amount float64, limit float64) (string, error) {
128128
orderNumber, err := wrapper.api.NewCreateOrderService().Type(binance.OrderTypeLimit).Side(binance.SideTypeSell).Symbol(MarketNameFor(market, wrapper)).Price(fmt.Sprint(limit)).Quantity(fmt.Sprint(amount)).Do(context.Background())
129129
return fmt.Sprint(orderNumber.ClientOrderID), err
130130
}
131131

132132
// BuyMarket performs a market buy action.
133-
func (wrapper BinanceWrapper) BuyMarket(market *environment.Market, amount float64) (string, error) {
133+
func (wrapper *BinanceWrapper) BuyMarket(market *environment.Market, amount float64) (string, error) {
134134
orderNumber, err := wrapper.api.NewCreateOrderService().Type(binance.OrderTypeMarket).Side(binance.SideTypeBuy).Symbol(MarketNameFor(market, wrapper)).Quantity(fmt.Sprint(amount)).Do(context.Background())
135135
return fmt.Sprint(orderNumber.ClientOrderID), err
136136
}
137137

138138
// SellMarket performs a market sell action.
139-
func (wrapper BinanceWrapper) SellMarket(market *environment.Market, amount float64) (string, error) {
139+
func (wrapper *BinanceWrapper) SellMarket(market *environment.Market, amount float64) (string, error) {
140140
orderNumber, err := wrapper.api.NewCreateOrderService().Type(binance.OrderTypeMarket).Side(binance.SideTypeSell).Symbol(MarketNameFor(market, wrapper)).Quantity(fmt.Sprint(amount)).Do(context.Background())
141141
return fmt.Sprint(orderNumber.ClientOrderID), err
142142
}
143143

144144
// GetTicker gets the updated ticker for a market.
145-
func (wrapper BinanceWrapper) GetTicker(market *environment.Market) (*environment.Ticker, error) {
145+
func (wrapper *BinanceWrapper) GetTicker(market *environment.Market) (*environment.Ticker, error) {
146146
binanceTicker, err := wrapper.api.NewBookTickerService().Symbol(MarketNameFor(market, wrapper)).Do(context.Background())
147147
if err != nil {
148148
return nil, err
@@ -159,7 +159,7 @@ func (wrapper BinanceWrapper) GetTicker(market *environment.Market) (*environmen
159159
}
160160

161161
// GetMarketSummary gets the current market summary.
162-
func (wrapper BinanceWrapper) GetMarketSummary(market *environment.Market) (*environment.MarketSummary, error) {
162+
func (wrapper *BinanceWrapper) GetMarketSummary(market *environment.Market) (*environment.MarketSummary, error) {
163163
if !wrapper.websocketOn {
164164
hilo, err := wrapper.api.NewListPriceChangeStatsService().Do(context.Background())
165165
if err != nil {
@@ -204,7 +204,7 @@ func (wrapper BinanceWrapper) GetMarketSummary(market *environment.Market) (*env
204204
}
205205

206206
// GetCandles gets the candle data from the exchange.
207-
func (wrapper BinanceWrapper) GetCandles(market *environment.Market) ([]environment.CandleStick, error) {
207+
func (wrapper *BinanceWrapper) GetCandles(market *environment.Market) ([]environment.CandleStick, error) {
208208
if !wrapper.websocketOn {
209209
binanceCandles, err := wrapper.api.NewKlinesService().Symbol(MarketNameFor(market, wrapper)).Do(context.Background())
210210
if err != nil {
@@ -241,7 +241,7 @@ func (wrapper BinanceWrapper) GetCandles(market *environment.Market) ([]environm
241241
}
242242

243243
// GetBalance gets the balance of the user of the specified currency.
244-
func (wrapper BinanceWrapper) GetBalance(symbol string) (*decimal.Decimal, error) {
244+
func (wrapper *BinanceWrapper) GetBalance(symbol string) (*decimal.Decimal, error) {
245245
binanceAccount, err := wrapper.api.NewGetAccountService().Do(context.Background())
246246
if err != nil {
247247
return nil, err
@@ -263,7 +263,7 @@ func (wrapper BinanceWrapper) GetBalance(symbol string) (*decimal.Decimal, error
263263
// CalculateTradingFees calculates the trading fees for an order on a specified market.
264264
//
265265
// NOTE: In Binance fees are currently hardcoded.
266-
func (wrapper BinanceWrapper) CalculateTradingFees(market *environment.Market, amount float64, limit float64, orderType TradeType) float64 {
266+
func (wrapper *BinanceWrapper) CalculateTradingFees(market *environment.Market, amount float64, limit float64, orderType TradeType) float64 {
267267
var feePercentage float64
268268
if orderType == MakerTrade {
269269
feePercentage = 0.0010
@@ -277,60 +277,44 @@ func (wrapper BinanceWrapper) CalculateTradingFees(market *environment.Market, a
277277
}
278278

279279
// CalculateWithdrawFees calculates the withdrawal fees on a specified market.
280-
func (wrapper BinanceWrapper) CalculateWithdrawFees(market *environment.Market, amount float64) float64 {
280+
func (wrapper *BinanceWrapper) CalculateWithdrawFees(market *environment.Market, amount float64) float64 {
281281
panic("Not Implemented")
282282
}
283283

284284
// FeedConnect connects to the feed of the exchange.
285-
func (wrapper BinanceWrapper) FeedConnect() {
286-
wrapper.websocketOn = true
287-
}
288-
289-
var unsubscribe = make(map[string]chan struct{})
290-
var unsubscribed = make(map[string]chan struct{})
291-
292-
// SubscribeMarketSummaryFeed subscribes to the Market Summary Feed service.
293-
func (wrapper BinanceWrapper) SubscribeMarketSummaryFeed(market *environment.Market) {
294-
if wrapper.websocketOn {
295-
doneC, stopC, err := binance.WsMarketStatServe(MarketNameFor(market, wrapper), func(event *binance.WsMarketStatEvent) {
296-
high, _ := decimal.NewFromString(event.HighPrice)
297-
low, _ := decimal.NewFromString(event.LowPrice)
298-
ask, _ := decimal.NewFromString(event.AskPrice)
299-
bid, _ := decimal.NewFromString(event.BidPrice)
300-
last, _ := decimal.NewFromString(event.LastPrice)
301-
volume, _ := decimal.NewFromString(event.BaseVolume)
302-
303-
wrapper.summaries.Set(market, &environment.MarketSummary{
304-
High: high,
305-
Low: low,
306-
Ask: ask,
307-
Bid: bid,
308-
Last: last,
309-
Volume: volume,
310-
})
311-
}, func(error) {})
312-
285+
func (wrapper *BinanceWrapper) FeedConnect(markets []*environment.Market) error {
286+
for _, m := range markets {
287+
err := wrapper.subscribeMarketSummaryFeed(m)
313288
if err != nil {
314-
panic(err)
289+
return err
315290
}
316-
317-
unsubscribe[MarketNameFor(market, wrapper)] = stopC
318-
unsubscribed[MarketNameFor(market, wrapper)] = doneC
319291
}
320-
}
321-
322-
// UnsubscribeMarketSummaryFeed unsubscribes from the Market Summary Feed service.
323-
func (wrapper BinanceWrapper) UnsubscribeMarketSummaryFeed(market *environment.Market) {
324-
if wrapper.websocketOn {
325-
tickerKey := MarketNameFor(market, wrapper)
292+
wrapper.websocketOn = true
326293

327-
unsubscribe[tickerKey] <- struct{}{}
294+
return nil
295+
}
328296

329-
<-unsubscribed[tickerKey]
297+
// SubscribeMarketSummaryFeed subscribes to the Market Summary Feed service.
298+
func (wrapper *BinanceWrapper) subscribeMarketSummaryFeed(market *environment.Market) error {
299+
_, _, err := binance.WsMarketStatServe(MarketNameFor(market, wrapper), func(event *binance.WsMarketStatEvent) {
300+
high, _ := decimal.NewFromString(event.HighPrice)
301+
low, _ := decimal.NewFromString(event.LowPrice)
302+
ask, _ := decimal.NewFromString(event.AskPrice)
303+
bid, _ := decimal.NewFromString(event.BidPrice)
304+
last, _ := decimal.NewFromString(event.LastPrice)
305+
volume, _ := decimal.NewFromString(event.BaseVolume)
330306

331-
close(unsubscribe[tickerKey])
332-
close(unsubscribed[tickerKey])
333-
delete(unsubscribe, tickerKey)
334-
delete(unsubscribed, tickerKey)
307+
wrapper.summaries.Set(market, &environment.MarketSummary{
308+
High: high,
309+
Low: low,
310+
Ask: ask,
311+
Bid: bid,
312+
Last: last,
313+
Volume: volume,
314+
})
315+
}, func(error) {})
316+
if err != nil {
317+
return err
335318
}
319+
return nil
336320
}

0 commit comments

Comments
 (0)