diff --git a/config/copytrader.yaml b/config/copytrader.yaml deleted file mode 100644 index d9fe53121..000000000 --- a/config/copytrader.yaml +++ /dev/null @@ -1,39 +0,0 @@ -sessions: - binance-master: - exchange: binance - envVarPrefix: BINANCE - futures: true - binance-slave: - exchange: binance - envVarPrefix: BINANCE_SLAVE - futures: true - -sync: - userDataStream: - trades: true - filledOrders: true - sessions: - - binance-master - - binance-slave - symbols: - - BTCUSDT - -crossExchangeStrategies: - -- on: binance-master - copytrader: - symbol: BTCUSDT - exchange: binance - -#- on: binance-slave -# copytrader: -# symbol: BTCUSDT -# exchange: binance - - -# sourceExchange: binanceMaster -# followerExchange: -# - binanceMaster -# - binanceSlave - - diff --git a/config/mirror.yaml b/config/mirror.yaml new file mode 100644 index 000000000..90ba039e3 --- /dev/null +++ b/config/mirror.yaml @@ -0,0 +1,17 @@ +sessions: + binance-master: + exchange: binance + envVarPrefix: BINANCE + futures: true + binance-slave: + exchange: binance + envVarPrefix: BINANCE_SLAVE + futures: true + +crossExchangeStrategies: + +- on: binance-master + mirror: + symbol: BTCUSDT + exchange: binance + diff --git a/pkg/cmd/builtin.go b/pkg/cmd/builtin.go index 582cab60f..1fae13414 100644 --- a/pkg/cmd/builtin.go +++ b/pkg/cmd/builtin.go @@ -5,7 +5,6 @@ import ( _ "github.com/c9s/bbgo/pkg/strategy/autoborrow" _ "github.com/c9s/bbgo/pkg/strategy/bollgrid" _ "github.com/c9s/bbgo/pkg/strategy/bollmaker" - _ "github.com/c9s/bbgo/pkg/strategy/copytrader" _ "github.com/c9s/bbgo/pkg/strategy/emastop" _ "github.com/c9s/bbgo/pkg/strategy/etf" _ "github.com/c9s/bbgo/pkg/strategy/ewoDgtrd" @@ -14,6 +13,7 @@ import ( _ "github.com/c9s/bbgo/pkg/strategy/funding" _ "github.com/c9s/bbgo/pkg/strategy/grid" _ "github.com/c9s/bbgo/pkg/strategy/kline" + _ "github.com/c9s/bbgo/pkg/strategy/mirror" _ "github.com/c9s/bbgo/pkg/strategy/pivotshort" _ "github.com/c9s/bbgo/pkg/strategy/pricealert" _ "github.com/c9s/bbgo/pkg/strategy/pricedrop" diff --git a/pkg/strategy/copytrader/strategy.go b/pkg/strategy/mirror/strategy.go similarity index 51% rename from pkg/strategy/copytrader/strategy.go rename to pkg/strategy/mirror/strategy.go index b9fbe9e21..a782a8031 100644 --- a/pkg/strategy/copytrader/strategy.go +++ b/pkg/strategy/mirror/strategy.go @@ -1,4 +1,4 @@ -package copytrader +package mirror import ( "context" @@ -9,7 +9,7 @@ import ( "github.com/sirupsen/logrus" ) -const ID = "copytrader" +const ID = "mirror" const stateKey = "state-v1" @@ -117,76 +117,9 @@ func (s *Strategy) CrossSubscribe(sessions map[string]*bbgo.ExchangeSession) { } func (s *Strategy) CrossRun(ctx context.Context, orderExecutionRouter bbgo.OrderExecutionRouter, sessions map[string]*bbgo.ExchangeSession) error { - //_ = s.Persistence.Sync(s) - // configure sessions - //sourceSession, ok := sessions[s.SourceExchange] - //if !ok { - // return fmt.Errorf("source exchange session %s is not defined", s.SourceExchange) - //} - - //s.sourceSession = sourceSession - - //for k, v := range s.FollowerExchange { - // followerSession, ok := sessions[k] - // if !ok { - // panic(fmt.Errorf("maker exchange session %s is not defined", v)) - // } - // s.followerSession[k] = followerSession - // - //} log.Info(sessions) - //sourceSession, _ := sessions["binance-master"] - //s.SourceSession = sourceSession - // - //for k, v := range sessions { - // // do not follower yourself - // if k != "binance-master" { - // s.FollowerSession[k], _ = sessions[k] - // log.Infof("subscribe follower session %s: %s, from env var: %s", k, v.Name, v.EnvVarPrefix) - // //if !ok { - // // panic(fmt.Errorf("follower session %s is not defined", v)) - // //} - // //s.FollowerSession[k].Subscribe(types.KLineChannel, s.Symbol, types.SubscribeOptions{Interval: "1m"}) - // } - //} - - //if !ok { - // return fmt.Errorf("source session market %s is not defined", s.Symbol) - //} - - //s.followerMarket, ok = s.sourceSession.Market(s.Symbol) - //if !ok { - // return fmt.Errorf("maker session market %s is not defined", s.Symbol) - //} - - // restore state - //instanceID := s.InstanceID() - //s.groupID = util.FNV32(instanceID) - //log.Infof("using group id %d from fnv(%s)", s.groupID, instanceID) - - //s.book = types.NewStreamBook(s.Symbol) - //s.book.BindStream(s.sourceSession.MarketDataStream) - - //for k, _ := range s.FollowerExchange { - // s.activeFollowerOrders[k] = bbgo.NewLocalActiveOrderBook(s.Symbol) - // s.activeFollowerOrders[k].BindStream(s.followerSession[k].UserDataStream) - // s.followerOrderStore[k] = bbgo.NewOrderStore(s.Symbol) - // s.followerOrderStore[k].BindStream(s.followerSession[k].UserDataStream) - //} - // - //s.sourceOrderStore = bbgo.NewOrderStore(s.Symbol) - //s.sourceOrderStore.BindStream(s.sourceSession.UserDataStream) - // If position is nil, we need to allocate a new position for calculation - //if s.Position == nil { - // s.Position = types.NewPositionFromMarket(s.Market) - //} - - //log.Infof("===") - //log.Info(s.SourceSession) - //log.Infof("===") - //log.Info(s.FollowerSession) sourceSession, ok := sessions["binance-master"] if !ok { panic(fmt.Errorf("source session %s is not defined", sourceSession.Name)) @@ -262,129 +195,6 @@ func (s *Strategy) CrossRun(ctx context.Context, orderExecutionRouter bbgo.Order } } }) - //}() - - //s.tradeCollector = bbgo.NewTradeCollector(s.Symbol, s.Position, s.orderStore) - - //if s.NotifyTrade { - // s.tradeCollector.OnTrade(func(trade types.Trade, profit, netProfit fixedpoint.Value) { - // s.Notifiability.Notify(trade) - // }) - //} - - //s.tradeCollector.OnTrade(func(trade types.Trade, profit, netProfit fixedpoint.Value) { - // c := trade.PositionChange() - // if trade.Exchange == s.sourceSession.ExchangeName { - // s.CoveredPosition = s.CoveredPosition.Add(c) - // } - // - // s.ProfitStats.AddTrade(trade) - // - // if profit.Compare(fixedpoint.Zero) == 0 { - // s.Environment.RecordPosition(s.Position, trade, nil) - // } else { - // log.Infof("%s generated profit: %v", s.Symbol, profit) - // - // p := s.Position.NewProfit(trade, profit, netProfit) - // p.Strategy = ID - // p.StrategyInstanceID = instanceID - // s.Notify(&p) - // s.ProfitStats.AddProfit(p) - // - // s.Environment.RecordPosition(s.Position, trade, &p) - // } - //}) - - //s.tradeCollector.OnPositionUpdate(func(position *types.Position) { - // s.Notifiability.Notify(position) - //}) - //s.tradeCollector.OnRecover(func(trade types.Trade) { - // s.Notifiability.Notify("Recover trade", trade) - //}) - //s.tradeCollector.BindStream(s.sourceSession.UserDataStream) - //s.tradeCollector.BindStream(s.makerSession.UserDataStream) - - //go func() { - - //defer func() { - // if err := s.activeFollowerOrders.GracefulCancel(context.Background(), - // s.makerSession.Exchange); err != nil { - // log.WithError(err).Errorf("can not cancel %s orders", s.Symbol) - // } - //}() - - // for { - // select { - // - // //case <-s.stopC: - // // log.Warnf("%s maker goroutine stopped, due to the stop signal", s.Symbol) - // // return - // - // case <-ctx.Done(): - // log.Warnf("%s maker goroutine stopped, due to the cancelled context", s.Symbol) - // return - // - // case <-quoteTicker.C: - // s.updateQuote(ctx, orderExecutionRouter) - // - // case <-reportTicker.C: - // s.Notifiability.Notify(&s.ProfitStats) - // - // case <-tradeScanTicker.C: - // log.Infof("scanning trades from %s ago...", tradeScanInterval) - // startTime := time.Now().Add(-tradeScanInterval) - // if err := s.tradeCollector.Recover(ctx, s.sourceSession.Exchange.(types.ExchangeTradeHistoryService), s.Symbol, startTime); err != nil { - // log.WithError(err).Errorf("query trades error") - // } - // - // case <-posTicker.C: - // // For positive position and positive covered position: - // // uncover position = +5 - +3 (covered position) = 2 - // // - // // For positive position and negative covered position: - // // uncover position = +5 - (-3) (covered position) = 8 - // // - // // meaning we bought 5 on MAX and sent buy order with 3 on binance - // // - // // For negative position: - // // uncover position = -5 - -3 (covered position) = -2 - // s.tradeCollector.Process() - // - // position := s.Position.GetBase() - // - // uncoverPosition := position.Sub(s.CoveredPosition) - // absPos := uncoverPosition.Abs() - // if !s.DisableHedge && absPos.Compare(s.sourceMarket.MinQuantity) > 0 { - // log.Infof("%s base position %v coveredPosition: %v uncoverPosition: %v", - // s.Symbol, - // position, - // s.CoveredPosition, - // uncoverPosition, - // ) - // - // s.Hedge(ctx, uncoverPosition.Neg()) - // } - // } - // } - //}() - - //s.Graceful.OnShutdown(func(ctx context.Context, wg *sync.WaitGroup) { - // defer wg.Done() - // - // close(s.stopC) - // - // // wait for the quoter to stop - // time.Sleep(s.UpdateInterval.Duration()) - // - // shutdownCtx, cancelShutdown := context.WithTimeout(context.TODO(), time.Minute) - // defer cancelShutdown() - // - // if err := s.activeMakerOrders.GracefulCancel(shutdownCtx, s.makerSession.Exchange); err != nil { - // log.WithError(err).Errorf("graceful cancel error") - // } - // - // s.Notify("%s: %s position", ID, s.Symbol, s.Position) - //}) return nil }