Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

FEATURE: add more converter #1706

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
153 changes: 153 additions & 0 deletions pkg/core/convert_manager.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
package core

import (
"github.com/c9s/bbgo/pkg/types"
"github.com/sirupsen/logrus"
)

type ConverterSetting struct {
SymbolConverter *SymbolConverter `json:"symbolConverter" yaml:"symbolConverter"`
CurrencyConverter *CurrencyConverter `json:"currencyConverter" yaml:"currencyConverter"`
}

func (s *ConverterSetting) getConverter() Converter {
if s.SymbolConverter != nil {
return s.SymbolConverter
}

if s.CurrencyConverter != nil {
return s.CurrencyConverter
}

return nil
}

func (s *ConverterSetting) InitializeConverter() (Converter, error) {
converter := s.getConverter()
if converter == nil {
return nil, nil
}

logrus.Infof("initializing converter %T ...", converter)
err := converter.Initialize()
return converter, err
}

// ConverterManager manages the converters for trade conversion
// It can be used to convert the trade symbol into the target symbol, or convert the price, volume into different units.
type ConverterManager struct {
ConverterSettings []ConverterSetting `json:"converters,omitempty" yaml:"converters,omitempty"`

converters []Converter
}

func (c *ConverterManager) Initialize() error {
for _, setting := range c.ConverterSettings {
converter, err := setting.InitializeConverter()
if err != nil {
return err
}

if converter != nil {
c.AddConverter(converter)
}
}

numConverters := len(c.converters)
logrus.Infof("%d converters loaded", numConverters)
return nil
}

func (c *ConverterManager) AddConverter(converter Converter) {
c.converters = append(c.converters, converter)
}

func (c *ConverterManager) ConvertOrder(order types.Order) types.Order {
if len(c.converters) == 0 {
return order
}

for _, converter := range c.converters {
convOrder, err := converter.ConvertOrder(order)
if err != nil {
logrus.WithError(err).Errorf("converter %+v error, order: %s", converter, order.String())
continue
}

order = convOrder
}

return order
}

func (c *ConverterManager) ConvertTrade(trade types.Trade) types.Trade {
if len(c.converters) == 0 {
return trade
}

for _, converter := range c.converters {
convTrade, err := converter.ConvertTrade(trade)
if err != nil {
logrus.WithError(err).Errorf("converter %+v error, trade: %s", converter, trade.String())
continue
}

trade = convTrade
}

return trade
}

func (c *ConverterManager) ConvertKLine(kline types.KLine) types.KLine {
if len(c.converters) == 0 {
return kline
}

for _, converter := range c.converters {
convKline, err := converter.ConvertKLine(kline)
if err != nil {
logrus.WithError(err).Errorf("converter %+v error, kline: %s", converter, kline.String())
continue
}

kline = convKline
}

return kline
}

func (c *ConverterManager) ConvertMarket(market types.Market) types.Market {
if len(c.converters) == 0 {
return market
}

for _, converter := range c.converters {
convMarket, err := converter.ConvertMarket(market)
if err != nil {
logrus.WithError(err).Errorf("converter %+v error, market: %+v", converter, market)
continue
}

market = convMarket
}

return market
}

func (c *ConverterManager) ConvertBalance(balance types.Balance) types.Balance {
if len(c.converters) == 0 {
return balance
}

for _, converter := range c.converters {
convBal, err := converter.ConvertBalance(balance)
if err != nil {
logrus.WithError(err).Errorf("converter %+v error, balance: %s", converter, balance.String())
continue
}

balance = convBal
}

return balance
}
212 changes: 212 additions & 0 deletions pkg/core/convert_manager_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,212 @@
package core

import (
"encoding/json"
"testing"

"github.com/c9s/bbgo/pkg/types"
"github.com/stretchr/testify/assert"
)

func TestInitializeConverter_ValidSymbolConverter(t *testing.T) {
setting := ConverterSetting{
SymbolConverter: &SymbolConverter{
FromSymbol: "MAXEXCHANGEUSDT",
ToSymbol: "MAXUSDT",
},
}
converter, err := setting.InitializeConverter()
assert.NoError(t, err)
assert.NotNil(t, converter)
}

func TestInitializeConverter_ValidCurrencyConverter(t *testing.T) {
setting := ConverterSetting{
CurrencyConverter: &CurrencyConverter{
FromCurrency: "MAXEXCHANGE",
ToCurrency: "MAX",
},
}
converter, err := setting.InitializeConverter()
assert.NoError(t, err)
assert.NotNil(t, converter)
}

func TestInitializeConverter_NoConverter(t *testing.T) {
setting := ConverterSetting{}
converter, err := setting.InitializeConverter()
assert.NoError(t, err)
assert.Nil(t, converter)
}

func TestInitialize_ValidConverters(t *testing.T) {
manager := ConverterManager{
ConverterSettings: []ConverterSetting{
{SymbolConverter: &SymbolConverter{
FromSymbol: "MAXEXCHANGEUSDT",
ToSymbol: "MAXUSDT",
}},
{CurrencyConverter: &CurrencyConverter{
FromCurrency: "MAXEXCHANGE",
ToCurrency: "MAX",
}},
},
}
err := manager.Initialize()
assert.NoError(t, err)
assert.Equal(t, 2, len(manager.converters))
}

func TestInitialize_NoConverters(t *testing.T) {
manager := ConverterManager{}
err := manager.Initialize()
assert.NoError(t, err)
assert.Equal(t, 0, len(manager.converters))
}

func TestConvertOrder_WithConverters(t *testing.T) {
jsonStr := `
{
"converters": [
{
"symbolConverter": {
"from": "MAXEXCHANGEUSDT",
"to": "MAXUSDT"
}
},
{
"currencyConverter": {
"from": "MAXEXCHANGE",
"to": "MAX"
}
}
]
}
`
manager := ConverterManager{}
err := json.Unmarshal([]byte(jsonStr), &manager)
assert.NoError(t, err)

order := types.Order{
SubmitOrder: types.SubmitOrder{
Symbol: "MAXEXCHANGEUSDT",
Market: types.Market{
Symbol: "MAXEXCHANGEUSDT",
QuoteCurrency: "USDT",
BaseCurrency: "MAXEXCHANGE",
},
},
}
err = manager.Initialize()
assert.NoError(t, err)
convertedOrder := manager.ConvertOrder(order)
assert.Equal(t, "MAXUSDT", convertedOrder.Symbol)
assert.Equal(t, "MAX", convertedOrder.Market.BaseCurrency)
assert.Equal(t, "USDT", convertedOrder.Market.QuoteCurrency)
assert.Equal(t, "MAXUSDT", convertedOrder.Market.Symbol)
}

func TestConvertOrder_NoConverters(t *testing.T) {
manager := ConverterManager{}
order := types.Order{}
err := manager.Initialize()
assert.NoError(t, err)
convertedOrder := manager.ConvertOrder(order)
assert.Equal(t, order, convertedOrder)
}

func TestConvertTrade_WithConverters(t *testing.T) {
manager := ConverterManager{}
converter := &CurrencyConverter{
FromCurrency: "MAXEXCHANGE",
ToCurrency: "MAX",
}
err := manager.Initialize()
assert.NoError(t, err)
manager.AddConverter(converter)

trade := types.Trade{}
convertedTrade := manager.ConvertTrade(trade)
assert.Equal(t, trade, convertedTrade)
}

func TestConvertTrade_NoConverters(t *testing.T) {
manager := ConverterManager{}
trade := types.Trade{}
err := manager.Initialize()
assert.NoError(t, err)
convertedTrade := manager.ConvertTrade(trade)
assert.Equal(t, trade, convertedTrade)
}

func TestConvertKLine_WithConverters(t *testing.T) {
manager := ConverterManager{}
converter := &CurrencyConverter{
FromCurrency: "MAXEXCHANGE",
ToCurrency: "MAX",
}
err := manager.Initialize()
assert.NoError(t, err)
manager.AddConverter(converter)

kline := types.KLine{}
convertedKline := manager.ConvertKLine(kline)
assert.Equal(t, kline, convertedKline)
}

func TestConvertKLine_NoConverters(t *testing.T) {
manager := ConverterManager{}
kline := types.KLine{}
err := manager.Initialize()
assert.NoError(t, err)
convertedKline := manager.ConvertKLine(kline)
assert.Equal(t, kline, convertedKline)
}

func TestConvertMarket_WithConverters(t *testing.T) {
manager := ConverterManager{}
converter := &CurrencyConverter{
FromCurrency: "MAXEXCHANGE",
ToCurrency: "MAX",
}
err := manager.Initialize()
assert.NoError(t, err)
manager.AddConverter(converter)

market := types.Market{}
convertedMarket := manager.ConvertMarket(market)
assert.Equal(t, market, convertedMarket)
}

func TestConvertMarket_NoConverters(t *testing.T) {
manager := ConverterManager{}
market := types.Market{}
err := manager.Initialize()
assert.NoError(t, err)
convertedMarket := manager.ConvertMarket(market)
assert.Equal(t, market, convertedMarket)
}

func TestConvertBalance_WithConverters(t *testing.T) {
manager := ConverterManager{}
converter := &CurrencyConverter{
FromCurrency: "MAXEXCHANGE",
ToCurrency: "MAX",
}
err := manager.Initialize()
assert.NoError(t, err)
manager.AddConverter(converter)

balance := types.Balance{}
convertedBalance := manager.ConvertBalance(balance)
assert.Equal(t, balance, convertedBalance)
}

func TestConvertBalance_NoConverters(t *testing.T) {
manager := ConverterManager{}
balance := types.Balance{}
err := manager.Initialize()
assert.NoError(t, err)
convertedBalance := manager.ConvertBalance(balance)
assert.Equal(t, balance, convertedBalance)
}
31 changes: 0 additions & 31 deletions pkg/core/converter_test.go

This file was deleted.

Loading
Loading