/
binancecreator.go
107 lines (90 loc) · 2.97 KB
/
binancecreator.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
package main
import (
"context"
"github.com/adshao/go-binance/v2"
"github.com/martinlindhe/notify"
"github.com/pkg/errors"
"github.com/shopspring/decimal"
"github.com/vadiminshakov/marti/entity"
"github.com/vadiminshakov/marti/services"
"github.com/vadiminshakov/marti/services/anomalydetector"
"github.com/vadiminshakov/marti/services/detector"
binancepricer "github.com/vadiminshakov/marti/services/pricer"
binancetrader "github.com/vadiminshakov/marti/services/trader"
"github.com/vadiminshakov/marti/services/windowfinder"
"go.uber.org/zap"
"time"
)
// binanceTradeServiceCreator creates trade service for binance exchange.
func binanceTradeServiceCreator(logger *zap.Logger, wf windowfinder.WindowFinder,
binanceClient *binance.Client, pair entity.Pair, usebalance decimal.Decimal,
pollPricesInterval time.Duration) (func(context.Context) error, error) {
pricer := binancepricer.NewPricer(binanceClient)
buyprice, window, err := wf.GetBuyPriceAndWindow()
if err != nil {
return nil, errors.Wrapf(err, "failed to find window for %s", pair.String())
}
detect, err := detector.NewDetector(binanceClient, usebalance, pair, buyprice, window)
if err != nil {
return nil, err
}
trader, err := binancetrader.NewTrader(binanceClient, pair)
if err != nil {
return nil, err
}
res, err := binanceClient.NewGetAccountService().Do(context.Background())
if err != nil {
return nil, err
}
var balanceFirstCurrency decimal.Decimal
var balanceSecondCurrency decimal.Decimal
for _, b := range res.Balances {
if b.Asset == pair.To {
balanceSecondCurrency, _ = decimal.NewFromString(b.Free)
}
if b.Asset == pair.From {
balanceFirstCurrency, _ = decimal.NewFromString(b.Free)
}
}
price, err := pricer.GetPrice(pair)
if err != nil {
return nil, err
}
percent := usebalance.Div(decimal.NewFromInt(100))
balanceSecondCurrency = balanceSecondCurrency.Div(price)
balanceSecondCurrency = balanceSecondCurrency.Mul(percent)
balanceSecondCurrency = balanceSecondCurrency.RoundFloor(5) // round down to 0,000x
amount := balanceSecondCurrency
if detect.LastAction() == entity.ActionBuy {
balanceFirstCurrency = balanceFirstCurrency.RoundFloor(5)
amount = balanceFirstCurrency
}
logger.Info("start",
zap.String("buyprice", buyprice.String()),
zap.String("window", window.String()),
zap.String("use "+pair.From, amount.String()))
anomdetector := anomalydetector.NewAnomalyDetector(pair, 30, decimal.NewFromInt(3))
ts := services.NewTradeService(logger, pair, amount, pricer, detect, trader, anomdetector)
return func(ctx context.Context) error {
t := time.NewTicker(pollPricesInterval)
for ctx.Err() == nil {
select {
case <-t.C:
te, err := ts.Trade()
if err != nil {
notify.Alert("marti", "alert", err.Error(), "")
t.Stop()
return err
}
if te != nil {
logger.Info(te.String())
notify.Alert("marti", "alert", te.String(), "")
}
case <-ctx.Done():
t.Stop()
return ctx.Err()
}
}
return ctx.Err()
}, nil
}