diff --git a/pkg/strategy/tri/market.go b/pkg/strategy/tri/market.go index eae513185..bf81fd192 100644 --- a/pkg/strategy/tri/market.go +++ b/pkg/strategy/tri/market.go @@ -2,6 +2,8 @@ package tri import ( "fmt" + "math" + "strconv" "github.com/c9s/bbgo/pkg/fixedpoint" "github.com/c9s/bbgo/pkg/sigchan" @@ -18,12 +20,39 @@ type ArbMarket struct { bestBid, bestAsk types.PriceVolume buyRate, sellRate float64 sigC sigchan.Chan + + truncateBaseQuantity, truncateQuoteQuantity QuantityTruncator } func (m *ArbMarket) String() string { return m.Symbol } +type QuantityTruncator func(value fixedpoint.Value) fixedpoint.Value + +func createBaseQuantityTruncator(m types.Market) QuantityTruncator { + var stepSizeFloat = m.StepSize.Float64() + var truncPrec = int(math.Round(math.Log10(stepSizeFloat) * -1.0)) + return createRoundedTruncator(truncPrec) +} + +func createPricePrecisionBasedQuoteQuantityTruncator(m types.Market) QuantityTruncator { + // note that MAX uses the price precision for its quote asset precision + return createRoundedTruncator(m.PricePrecision) +} + +func createRoundedTruncator(truncPrec int) QuantityTruncator { + var truncPow10 = math.Pow10(truncPrec) + var roundPrec = truncPrec + 1 + var roundPow10 = math.Pow10(roundPrec) + return func(value fixedpoint.Value) fixedpoint.Value { + v := value.Float64() + v = math.Trunc(math.Round(v*roundPow10)/10.0) / truncPow10 + s := strconv.FormatFloat(v, 'f', truncPrec, 64) + return fixedpoint.MustNewFromString(s) + } +} + func (m *ArbMarket) getInitialBalance(balances types.BalanceMap, dir int) (fixedpoint.Value, string) { if dir == 1 { // sell 1 BTC -> 19000 USDT b, ok := balances[m.BaseCurrency] @@ -31,14 +60,14 @@ func (m *ArbMarket) getInitialBalance(balances types.BalanceMap, dir int) (fixed return fixedpoint.Zero, m.BaseCurrency } - return m.market.TruncateQuantity(b.Available), m.BaseCurrency + return m.truncateBaseQuantity(b.Available), m.BaseCurrency } else if dir == -1 { b, ok := balances[m.QuoteCurrency] if !ok { return fixedpoint.Zero, m.QuoteCurrency } - return m.market.TruncateQuantity(b.Available), m.QuoteCurrency + return m.truncateQuoteQuantity(b.Available), m.QuoteCurrency } return fixedpoint.Zero, "" @@ -75,24 +104,22 @@ func (m *ArbMarket) updateRate() { func (m *ArbMarket) newOrder(dir int, transitingQuantity float64) (types.SubmitOrder, float64) { if dir == 1 { // sell ETH -> BTC, sell USDT -> TWD - q, r := fitQuantityByBase(m.market.TruncateQuantity(m.bestBid.Volume).Float64(), transitingQuantity) - fq := fixedpoint.NewFromFloat(q) + q, r := fitQuantityByBase(m.truncateBaseQuantity(m.bestBid.Volume).Float64(), transitingQuantity) return types.SubmitOrder{ Symbol: m.Symbol, Side: types.SideTypeSell, Type: types.OrderTypeLimit, - Quantity: fq, + Quantity: fixedpoint.NewFromFloat(q), Price: m.bestBid.Price, Market: m.market, }, r } else if dir == -1 { // use 1 BTC to buy X ETH - q, r := fitQuantityByQuote(m.bestAsk.Price.Float64(), m.market.TruncateQuantity(m.bestAsk.Volume).Float64(), transitingQuantity) - fq := fixedpoint.NewFromFloat(q) + q, r := fitQuantityByQuote(m.bestAsk.Price.Float64(), m.truncateBaseQuantity(m.bestAsk.Volume).Float64(), transitingQuantity) return types.SubmitOrder{ Symbol: m.Symbol, Side: types.SideTypeBuy, Type: types.OrderTypeLimit, - Quantity: fq, + Quantity: fixedpoint.NewFromFloat(q), Price: m.bestAsk.Price, Market: m.market, }, r diff --git a/pkg/strategy/tri/strategy.go b/pkg/strategy/tri/strategy.go index ec3c128c9..c4d8b39e3 100644 --- a/pkg/strategy/tri/strategy.go +++ b/pkg/strategy/tri/strategy.go @@ -773,11 +773,13 @@ func (s *Strategy) buildArbMarkets(session *bbgo.ExchangeSession, symbols []stri } m := &ArbMarket{ - Symbol: symbol, - market: market, - BaseCurrency: market.BaseCurrency, - QuoteCurrency: market.QuoteCurrency, - sigC: sigC, + Symbol: symbol, + market: market, + BaseCurrency: market.BaseCurrency, + QuoteCurrency: market.QuoteCurrency, + sigC: sigC, + truncateBaseQuantity: createBaseQuantityTruncator(market), + truncateQuoteQuantity: createPricePrecisionBasedQuoteQuantityTruncator(market), } if separateStream {