Skip to content

Commit 16aa0b0

Browse files
refactor(telegram): improve error handling (#113)
1 parent d344e90 commit 16aa0b0

File tree

7 files changed

+72
-31
lines changed

7 files changed

+72
-31
lines changed

exchange/binance.go

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -114,14 +114,17 @@ func (b *Binance) AssetsInfo(pair string) model.AssetInfo {
114114
}
115115

116116
func (b *Binance) validate(pair string, quantity float64) error {
117-
118117
info, ok := b.assetsInfo[pair]
119118
if !ok {
120119
return ErrInvalidAsset
121120
}
122121

123122
if quantity > info.MaxQuantity || quantity < info.MinQuantity {
124-
return fmt.Errorf("%w: min: %f max: %f", ErrInvalidQuantity, info.MinQuantity, info.MaxQuantity)
123+
return &OrderError{
124+
Err: fmt.Errorf("%w: min: %f max: %f", ErrInvalidQuantity, info.MinQuantity, info.MaxQuantity),
125+
Pair: pair,
126+
Quantity: quantity,
127+
}
125128
}
126129

127130
return nil

exchange/exchange.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,16 @@ type Subscription struct {
3838
consumer DataFeedConsumer
3939
}
4040

41+
type OrderError struct {
42+
Err error
43+
Pair string
44+
Quantity float64
45+
}
46+
47+
func (o *OrderError) Error() string {
48+
return fmt.Sprintf("order error: %v", o.Err)
49+
}
50+
4151
type DataFeedConsumer func(model.Candle)
4252

4353
func NewDataFeed(exchange service.Exchange) *DataFeedSubscription {

exchange/paperwallet.go

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,10 @@ import (
99
"sync"
1010
"time"
1111

12-
"github.com/rodrigo-brito/ninjabot/service"
13-
1412
log "github.com/sirupsen/logrus"
1513

1614
"github.com/rodrigo-brito/ninjabot/model"
15+
"github.com/rodrigo-brito/ninjabot/service"
1716
)
1817

1918
type assetInfo struct {
@@ -217,7 +216,11 @@ func (p *PaperWallet) Summary() {
217216

218217
func (p *PaperWallet) lockFunds(asset string, amount float64) error {
219218
if value, ok := p.assets[asset]; !ok || value.Free < amount {
220-
return ErrInsufficientFunds
219+
return &OrderError{
220+
Err: ErrInsufficientFunds,
221+
Pair: asset,
222+
Quantity: amount,
223+
}
221224
}
222225
p.assets[asset].Free = p.assets[asset].Free - amount
223226
p.assets[asset].Lock = p.assets[asset].Lock + amount
@@ -447,7 +450,11 @@ func (p *PaperWallet) createOrderMarket(side model.SideType, pair string, size f
447450
asset, quote := SplitAssetQuote(pair)
448451
if side == model.SideTypeSell {
449452
if value, ok := p.assets[asset]; !ok || value.Free < size {
450-
return model.Order{}, ErrInsufficientFunds
453+
return model.Order{}, &OrderError{
454+
Err: ErrInsufficientFunds,
455+
Pair: pair,
456+
Quantity: size,
457+
}
451458
}
452459
if _, ok := p.assets[quote]; !ok {
453460
p.assets[quote] = &assetInfo{}
@@ -456,7 +463,11 @@ func (p *PaperWallet) createOrderMarket(side model.SideType, pair string, size f
456463
p.assets[quote].Free = p.assets[quote].Free + p.lastCandle[pair].Close*size
457464
} else {
458465
if value, ok := p.assets[quote]; !ok || value.Free < size*p.lastCandle[pair].Close {
459-
return model.Order{}, ErrInsufficientFunds
466+
return model.Order{}, &OrderError{
467+
Err: ErrInsufficientFunds,
468+
Pair: pair,
469+
Quantity: size,
470+
}
460471
}
461472
if _, ok := p.assets[asset]; !ok {
462473
p.assets[asset] = &assetInfo{}

exchange/paperwallet_test.go

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,10 @@ func TestPaperWallet_OrderLimit(t *testing.T) {
3535
// try to buy again without funds
3636
order, err = wallet.CreateOrderLimit(model.SideTypeBuy, "BTCUSDT", 1, 100)
3737
require.Empty(t, order)
38-
require.Equal(t, ErrInsufficientFunds, err)
38+
require.Equal(t, &OrderError{
39+
Err: ErrInsufficientFunds,
40+
Pair: "USDT",
41+
Quantity: 100}, err)
3942

4043
// try to sell and profit 100 USDT
4144
order, err = wallet.CreateOrderLimit(model.SideTypeSell, "BTCUSDT", 1, 200)
@@ -138,7 +141,10 @@ func TestPaperWallet_OrderMarket(t *testing.T) {
138141

139142
// insufficient funds
140143
order, err = wallet.CreateOrderMarket(model.SideTypeBuy, "BTCUSDT", 100)
141-
require.Equal(t, ErrInsufficientFunds, err)
144+
require.Equal(t, &OrderError{
145+
Err: ErrInsufficientFunds,
146+
Pair: "BTCUSDT",
147+
Quantity: 100}, err)
142148
require.Empty(t, order)
143149

144150
// sell
@@ -177,7 +183,10 @@ func TestPaperWallet_OrderOCO(t *testing.T) {
177183

178184
// insufficient funds
179185
orders, err = wallet.CreateOrderOCO(model.SideTypeSell, "BTCUSDT", 1, 100, 40, 39)
180-
require.Equal(t, ErrInsufficientFunds, err)
186+
require.Equal(t, &OrderError{
187+
Err: ErrInsufficientFunds,
188+
Pair: "BTC",
189+
Quantity: 1}, err)
181190
require.Nil(t, orders)
182191

183192
// execute stop and cancel target

ninjabot.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -276,7 +276,7 @@ func (n *NinjaBot) backtestCandles() {
276276
}
277277

278278
if err := progressBar.Add(1); err != nil {
279-
log.Warningf("update progresbar fail: %s", err.Error())
279+
log.Warningf("update progresbar fail: %v", err)
280280
}
281281
}
282282
}

notification/telegram.go

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package notification
22

33
import (
4+
"errors"
45
"fmt"
56
"regexp"
67
"strconv"
@@ -250,7 +251,6 @@ func (t telegram) BuyHandle(m *tb.Message) {
250251

251252
order, err := t.orderController.CreateOrderMarketQuote(model.SideTypeBuy, pair, amount)
252253
if err != nil {
253-
log.Error(err)
254254
return
255255
}
256256
log.Info("[TELEGRAM]: BUY ORDER CREATED: ", order)
@@ -290,15 +290,12 @@ func (t telegram) SellHandle(m *tb.Message) {
290290
if command["percent"] != "" {
291291
asset, _, err := t.orderController.Position(pair)
292292
if err != nil {
293-
log.Error(err)
294-
t.OnError(err)
295293
return
296294
}
297295

298296
amount = amount * asset / 100.0
299297
order, err := t.orderController.CreateOrderMarket(model.SideTypeSell, pair, amount)
300298
if err != nil {
301-
log.Error(err)
302299
return
303300
}
304301
log.Info("[TELEGRAM]: SELL ORDER CREATED: ", order)
@@ -307,7 +304,6 @@ func (t telegram) SellHandle(m *tb.Message) {
307304

308305
order, err := t.orderController.CreateOrderMarketQuote(model.SideTypeSell, pair, amount)
309306
if err != nil {
310-
log.Error(err)
311307
return
312308
}
313309
log.Info("[TELEGRAM]: SELL ORDER CREATED: ", order)
@@ -369,6 +365,18 @@ func (t telegram) OnOrder(order model.Order) {
369365

370366
func (t telegram) OnError(err error) {
371367
title := "🛑 ERROR"
372-
message := fmt.Sprintf("%s\n-----\n%s", title, err)
373-
t.Notify(message)
368+
369+
var orderError *exchange.OrderError
370+
if errors.As(err, &orderError) {
371+
message := fmt.Sprintf(`%s
372+
-----
373+
Pair: %s
374+
Quantity: %.4f
375+
-----
376+
%s`, title, orderError.Pair, orderError.Quantity, orderError.Err)
377+
t.Notify(message)
378+
return
379+
}
380+
381+
t.Notify(fmt.Sprintf("%s\n-----\n%s", title, err))
374382
}

order/controller.go

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -198,14 +198,14 @@ func (c *Controller) processTrade(order *model.Order) {
198198
// register order volume
199199
c.Results[order.Pair].Volume += order.Price * order.Quantity
200200

201-
// calculate profit only for sell orders
201+
// calculate profit only to sell orders
202202
if order.Side != model.SideTypeSell {
203203
return
204204
}
205205

206206
profitValue, profit, err := c.calculateProfit(order)
207207
if err != nil {
208-
c.notifyError(fmt.Errorf("order/controller storage: %s", err))
208+
c.notifyError(err)
209209
return
210210
}
211211

@@ -231,7 +231,7 @@ func (c *Controller) updateOrders() {
231231
model.OrderStatusTypePendingCancel,
232232
))
233233
if err != nil {
234-
c.notifyError(fmt.Errorf("orderController/start: %s", err))
234+
c.notifyError(err)
235235
c.mtx.Unlock()
236236
return
237237
}
@@ -253,7 +253,7 @@ func (c *Controller) updateOrders() {
253253
excOrder.ID = order.ID
254254
err = c.storage.UpdateOrder(&excOrder)
255255
if err != nil {
256-
c.notifyError(fmt.Errorf("orderControler/update: %s", err))
256+
c.notifyError(err)
257257
continue
258258
}
259259

@@ -331,14 +331,14 @@ func (c *Controller) CreateOrderOCO(side model.SideType, pair string, size, pric
331331
log.Infof("[ORDER] Creating OCO order for %s", pair)
332332
orders, err := c.exchange.CreateOrderOCO(side, pair, size, price, stop, stopLimit)
333333
if err != nil {
334-
c.notifyError(fmt.Errorf("order/controller exchange: %s", err))
334+
c.notifyError(err)
335335
return nil, err
336336
}
337337

338338
for i := range orders {
339339
err := c.storage.CreateOrder(&orders[i])
340340
if err != nil {
341-
c.notifyError(fmt.Errorf("order/controller storage: %s", err))
341+
c.notifyError(err)
342342
return nil, err
343343
}
344344
go c.orderFeed.Publish(orders[i], true)
@@ -354,13 +354,13 @@ func (c *Controller) CreateOrderLimit(side model.SideType, pair string, size, li
354354
log.Infof("[ORDER] Creating LIMIT %s order for %s", side, pair)
355355
order, err := c.exchange.CreateOrderLimit(side, pair, size, limit)
356356
if err != nil {
357-
c.notifyError(fmt.Errorf("order/controller exchange: %s", err))
357+
c.notifyError(err)
358358
return model.Order{}, err
359359
}
360360

361361
err = c.storage.CreateOrder(&order)
362362
if err != nil {
363-
c.notifyError(fmt.Errorf("order/controller storage: %s", err))
363+
c.notifyError(err)
364364
return model.Order{}, err
365365
}
366366
go c.orderFeed.Publish(order, true)
@@ -375,13 +375,13 @@ func (c *Controller) CreateOrderMarketQuote(side model.SideType, pair string, am
375375
log.Infof("[ORDER] Creating MARKET %s order for %s", side, pair)
376376
order, err := c.exchange.CreateOrderMarketQuote(side, pair, amount)
377377
if err != nil {
378-
c.notifyError(fmt.Errorf("order/controller exchange: %s", err))
378+
c.notifyError(err)
379379
return model.Order{}, err
380380
}
381381

382382
err = c.storage.CreateOrder(&order)
383383
if err != nil {
384-
c.notifyError(fmt.Errorf("order/controller storage: %s", err))
384+
c.notifyError(err)
385385
return model.Order{}, err
386386
}
387387

@@ -399,13 +399,13 @@ func (c *Controller) CreateOrderMarket(side model.SideType, pair string, size fl
399399
log.Infof("[ORDER] Creating MARKET %s order for %s", side, pair)
400400
order, err := c.exchange.CreateOrderMarket(side, pair, size)
401401
if err != nil {
402-
c.notifyError(fmt.Errorf("order/controller exchange: %s", err))
402+
c.notifyError(err)
403403
return model.Order{}, err
404404
}
405405

406406
err = c.storage.CreateOrder(&order)
407407
if err != nil {
408-
c.notifyError(fmt.Errorf("order/controller storage: %s", err))
408+
c.notifyError(err)
409409
return model.Order{}, err
410410
}
411411

@@ -429,7 +429,7 @@ func (c *Controller) Cancel(order model.Order) error {
429429
order.Status = model.OrderStatusTypePendingCancel
430430
err = c.storage.UpdateOrder(&order)
431431
if err != nil {
432-
c.notifyError(fmt.Errorf("order/controller storage: %s", err))
432+
c.notifyError(err)
433433
return err
434434
}
435435
log.Infof("[ORDER CANCELED] %s", order)

0 commit comments

Comments
 (0)