mirror of
https://github.com/c9s/bbgo.git
synced 2024-11-10 17:13:51 +00:00
Merge pull request #348 from austin362667/refactor-position
types: refactor Position and related files
This commit is contained in:
commit
8fba55707c
|
@ -3,7 +3,6 @@ package pnl
|
||||||
import (
|
import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/c9s/bbgo/pkg/bbgo"
|
|
||||||
"github.com/c9s/bbgo/pkg/fixedpoint"
|
"github.com/c9s/bbgo/pkg/fixedpoint"
|
||||||
"github.com/c9s/bbgo/pkg/types"
|
"github.com/c9s/bbgo/pkg/types"
|
||||||
)
|
)
|
||||||
|
@ -33,8 +32,8 @@ func (c *AverageCostCalculator) Calculate(symbol string, trades []types.Trade, c
|
||||||
|
|
||||||
var currencyFees = map[string]float64{}
|
var currencyFees = map[string]float64{}
|
||||||
|
|
||||||
var position = bbgo.NewPositionFromMarket(c.Market)
|
var position = types.NewPositionFromMarket(c.Market)
|
||||||
position.SetFeeRate(bbgo.ExchangeFee{
|
position.SetFeeRate(types.ExchangeFee{
|
||||||
// binance vip 0 uses 0.075%
|
// binance vip 0 uses 0.075%
|
||||||
MakerFeeRate: fixedpoint.NewFromFloat(0.075 * 0.01),
|
MakerFeeRate: fixedpoint.NewFromFloat(0.075 * 0.01),
|
||||||
TakerFeeRate: fixedpoint.NewFromFloat(0.075 * 0.01),
|
TakerFeeRate: fixedpoint.NewFromFloat(0.075 * 0.01),
|
||||||
|
|
|
@ -199,7 +199,7 @@ type ExchangeSession struct {
|
||||||
// marketDataStores contains the market data store of each market
|
// marketDataStores contains the market data store of each market
|
||||||
marketDataStores map[string]*MarketDataStore
|
marketDataStores map[string]*MarketDataStore
|
||||||
|
|
||||||
positions map[string]*Position
|
positions map[string]*types.Position
|
||||||
|
|
||||||
// standard indicators of each market
|
// standard indicators of each market
|
||||||
standardIndicatorSets map[string]*StandardIndicatorSet
|
standardIndicatorSets map[string]*StandardIndicatorSet
|
||||||
|
@ -236,7 +236,7 @@ func NewExchangeSession(name string, exchange types.Exchange) *ExchangeSession {
|
||||||
markets: make(map[string]types.Market),
|
markets: make(map[string]types.Market),
|
||||||
startPrices: make(map[string]float64),
|
startPrices: make(map[string]float64),
|
||||||
lastPrices: make(map[string]float64),
|
lastPrices: make(map[string]float64),
|
||||||
positions: make(map[string]*Position),
|
positions: make(map[string]*types.Position),
|
||||||
marketDataStores: make(map[string]*MarketDataStore),
|
marketDataStores: make(map[string]*MarketDataStore),
|
||||||
standardIndicatorSets: make(map[string]*StandardIndicatorSet),
|
standardIndicatorSets: make(map[string]*StandardIndicatorSet),
|
||||||
orderStores: make(map[string]*OrderStore),
|
orderStores: make(map[string]*OrderStore),
|
||||||
|
@ -388,7 +388,7 @@ func (session *ExchangeSession) initSymbol(ctx context.Context, environ *Environ
|
||||||
session.Trades[symbol].Append(trade)
|
session.Trades[symbol].Append(trade)
|
||||||
})
|
})
|
||||||
|
|
||||||
position := &Position{
|
position := &types.Position{
|
||||||
Symbol: symbol,
|
Symbol: symbol,
|
||||||
BaseCurrency: market.BaseCurrency,
|
BaseCurrency: market.BaseCurrency,
|
||||||
QuoteCurrency: market.QuoteCurrency,
|
QuoteCurrency: market.QuoteCurrency,
|
||||||
|
@ -475,7 +475,7 @@ func (session *ExchangeSession) StandardIndicatorSet(symbol string) (*StandardIn
|
||||||
return set, ok
|
return set, ok
|
||||||
}
|
}
|
||||||
|
|
||||||
func (session *ExchangeSession) Position(symbol string) (pos *Position, ok bool) {
|
func (session *ExchangeSession) Position(symbol string) (pos *types.Position, ok bool) {
|
||||||
pos, ok = session.positions[symbol]
|
pos, ok = session.positions[symbol]
|
||||||
if ok {
|
if ok {
|
||||||
return pos, ok
|
return pos, ok
|
||||||
|
@ -486,7 +486,7 @@ func (session *ExchangeSession) Position(symbol string) (pos *Position, ok bool)
|
||||||
return nil, false
|
return nil, false
|
||||||
}
|
}
|
||||||
|
|
||||||
pos = &Position{
|
pos = &types.Position{
|
||||||
Symbol: symbol,
|
Symbol: symbol,
|
||||||
BaseCurrency: market.BaseCurrency,
|
BaseCurrency: market.BaseCurrency,
|
||||||
QuoteCurrency: market.QuoteCurrency,
|
QuoteCurrency: market.QuoteCurrency,
|
||||||
|
@ -496,7 +496,7 @@ func (session *ExchangeSession) Position(symbol string) (pos *Position, ok bool)
|
||||||
return pos, ok
|
return pos, ok
|
||||||
}
|
}
|
||||||
|
|
||||||
func (session *ExchangeSession) Positions() map[string]*Position {
|
func (session *ExchangeSession) Positions() map[string]*types.Position {
|
||||||
return session.positions
|
return session.positions
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -712,7 +712,7 @@ func InitExchangeSession(name string, session *ExchangeSession) error {
|
||||||
session.lastPrices = make(map[string]float64)
|
session.lastPrices = make(map[string]float64)
|
||||||
session.startPrices = make(map[string]float64)
|
session.startPrices = make(map[string]float64)
|
||||||
session.marketDataStores = make(map[string]*MarketDataStore)
|
session.marketDataStores = make(map[string]*MarketDataStore)
|
||||||
session.positions = make(map[string]*Position)
|
session.positions = make(map[string]*types.Position)
|
||||||
session.standardIndicatorSets = make(map[string]*StandardIndicatorSet)
|
session.standardIndicatorSets = make(map[string]*StandardIndicatorSet)
|
||||||
session.orderStores = make(map[string]*OrderStore)
|
session.orderStores = make(map[string]*OrderStore)
|
||||||
session.OrderExecutor = &ExchangeOrderExecutor{
|
session.OrderExecutor = &ExchangeOrderExecutor{
|
||||||
|
|
|
@ -16,15 +16,15 @@ type TradeCollector struct {
|
||||||
|
|
||||||
tradeStore *TradeStore
|
tradeStore *TradeStore
|
||||||
tradeC chan types.Trade
|
tradeC chan types.Trade
|
||||||
position *Position
|
position *types.Position
|
||||||
orderStore *OrderStore
|
orderStore *OrderStore
|
||||||
|
|
||||||
tradeCallbacks []func(trade types.Trade)
|
tradeCallbacks []func(trade types.Trade)
|
||||||
positionUpdateCallbacks []func(position *Position)
|
positionUpdateCallbacks []func(position *types.Position)
|
||||||
profitCallbacks []func(trade types.Trade, profit, netProfit fixedpoint.Value)
|
profitCallbacks []func(trade types.Trade, profit, netProfit fixedpoint.Value)
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewTradeCollector(symbol string, position *Position, orderStore *OrderStore) *TradeCollector {
|
func NewTradeCollector(symbol string, position *types.Position, orderStore *OrderStore) *TradeCollector {
|
||||||
return &TradeCollector{
|
return &TradeCollector{
|
||||||
Symbol: symbol,
|
Symbol: symbol,
|
||||||
orderSig: sigchan.New(1),
|
orderSig: sigchan.New(1),
|
||||||
|
|
|
@ -17,11 +17,11 @@ func (c *TradeCollector) EmitTrade(trade types.Trade) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *TradeCollector) OnPositionUpdate(cb func(position *Position)) {
|
func (c *TradeCollector) OnPositionUpdate(cb func(position *types.Position)) {
|
||||||
c.positionUpdateCallbacks = append(c.positionUpdateCallbacks, cb)
|
c.positionUpdateCallbacks = append(c.positionUpdateCallbacks, cb)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *TradeCollector) EmitPositionUpdate(position *Position) {
|
func (c *TradeCollector) EmitPositionUpdate(position *types.Position) {
|
||||||
for _, cb := range c.positionUpdateCallbacks {
|
for _, cb := range c.positionUpdateCallbacks {
|
||||||
cb(position)
|
cb(position)
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,7 +37,7 @@ type TwapExecution struct {
|
||||||
|
|
||||||
activeMakerOrders *LocalActiveOrderBook
|
activeMakerOrders *LocalActiveOrderBook
|
||||||
orderStore *OrderStore
|
orderStore *OrderStore
|
||||||
position *Position
|
position *types.Position
|
||||||
|
|
||||||
executionCtx context.Context
|
executionCtx context.Context
|
||||||
cancelExecution context.CancelFunc
|
cancelExecution context.CancelFunc
|
||||||
|
@ -444,7 +444,7 @@ func (e *TwapExecution) Run(parentCtx context.Context) error {
|
||||||
|
|
||||||
e.userDataStream = e.Session.Exchange.NewStream()
|
e.userDataStream = e.Session.Exchange.NewStream()
|
||||||
e.userDataStream.OnTradeUpdate(e.handleTradeUpdate)
|
e.userDataStream.OnTradeUpdate(e.handleTradeUpdate)
|
||||||
e.position = &Position{
|
e.position = &types.Position{
|
||||||
Symbol: e.Symbol,
|
Symbol: e.Symbol,
|
||||||
BaseCurrency: e.market.BaseCurrency,
|
BaseCurrency: e.market.BaseCurrency,
|
||||||
QuoteCurrency: e.market.QuoteCurrency,
|
QuoteCurrency: e.market.QuoteCurrency,
|
||||||
|
|
|
@ -30,7 +30,7 @@ func init() {
|
||||||
}
|
}
|
||||||
|
|
||||||
type State struct {
|
type State struct {
|
||||||
Position *bbgo.Position `json:"position,omitempty"`
|
Position *types.Position `json:"position,omitempty"`
|
||||||
ProfitStats bbgo.ProfitStats `json:"profitStats,omitempty"`
|
ProfitStats bbgo.ProfitStats `json:"profitStats,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -119,7 +119,7 @@ func (s *Strategy) LoadState() error {
|
||||||
|
|
||||||
// if position is nil, we need to allocate a new position for calculation
|
// if position is nil, we need to allocate a new position for calculation
|
||||||
if s.state.Position == nil {
|
if s.state.Position == nil {
|
||||||
s.state.Position = bbgo.NewPositionFromMarket(s.market)
|
s.state.Position = types.NewPositionFromMarket(s.market)
|
||||||
}
|
}
|
||||||
|
|
||||||
// init profit states
|
// init profit states
|
||||||
|
@ -297,7 +297,7 @@ func (s *Strategy) Run(ctx context.Context, orderExecutor bbgo.OrderExecutor, se
|
||||||
s.state.ProfitStats.AddTrade(trade)
|
s.state.ProfitStats.AddTrade(trade)
|
||||||
})
|
})
|
||||||
|
|
||||||
s.tradeCollector.OnPositionUpdate(func(position *bbgo.Position) {
|
s.tradeCollector.OnPositionUpdate(func(position *types.Position) {
|
||||||
log.Infof("position changed: %s", s.state.Position)
|
log.Infof("position changed: %s", s.state.Position)
|
||||||
s.Notify(s.state.Position)
|
s.Notify(s.state.Position)
|
||||||
})
|
})
|
||||||
|
|
|
@ -31,7 +31,7 @@ type State struct {
|
||||||
Orders []types.SubmitOrder `json:"orders,omitempty"`
|
Orders []types.SubmitOrder `json:"orders,omitempty"`
|
||||||
FilledBuyGrids map[fixedpoint.Value]struct{} `json:"filledBuyGrids"`
|
FilledBuyGrids map[fixedpoint.Value]struct{} `json:"filledBuyGrids"`
|
||||||
FilledSellGrids map[fixedpoint.Value]struct{} `json:"filledSellGrids"`
|
FilledSellGrids map[fixedpoint.Value]struct{} `json:"filledSellGrids"`
|
||||||
Position *bbgo.Position `json:"position,omitempty"`
|
Position *types.Position `json:"position,omitempty"`
|
||||||
|
|
||||||
AccumulativeArbitrageProfit fixedpoint.Value `json:"accumulativeArbitrageProfit"`
|
AccumulativeArbitrageProfit fixedpoint.Value `json:"accumulativeArbitrageProfit"`
|
||||||
|
|
||||||
|
@ -511,7 +511,7 @@ func (s *Strategy) LoadState() error {
|
||||||
FilledBuyGrids: make(map[fixedpoint.Value]struct{}),
|
FilledBuyGrids: make(map[fixedpoint.Value]struct{}),
|
||||||
FilledSellGrids: make(map[fixedpoint.Value]struct{}),
|
FilledSellGrids: make(map[fixedpoint.Value]struct{}),
|
||||||
ArbitrageOrders: make(map[uint64]types.Order),
|
ArbitrageOrders: make(map[uint64]types.Order),
|
||||||
Position: bbgo.NewPositionFromMarket(s.Market),
|
Position: types.NewPositionFromMarket(s.Market),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
s.state = &state
|
s.state = &state
|
||||||
|
@ -591,16 +591,16 @@ func (s *Strategy) Run(ctx context.Context, orderExecutor bbgo.OrderExecutor, se
|
||||||
})
|
})
|
||||||
|
|
||||||
/*
|
/*
|
||||||
if s.TradeService != nil {
|
if s.TradeService != nil {
|
||||||
s.tradeCollector.OnTrade(func(trade types.Trade) {
|
s.tradeCollector.OnTrade(func(trade types.Trade) {
|
||||||
if err := s.TradeService.Mark(ctx, trade.ID, ID); err != nil {
|
if err := s.TradeService.Mark(ctx, trade.ID, ID); err != nil {
|
||||||
log.WithError(err).Error("trade mark error")
|
log.WithError(err).Error("trade mark error")
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
s.tradeCollector.OnPositionUpdate(func(position *bbgo.Position) {
|
s.tradeCollector.OnPositionUpdate(func(position *types.Position) {
|
||||||
s.Notifiability.Notify(position)
|
s.Notifiability.Notify(position)
|
||||||
})
|
})
|
||||||
s.tradeCollector.BindStream(session.UserDataStream)
|
s.tradeCollector.BindStream(session.UserDataStream)
|
||||||
|
|
|
@ -27,7 +27,7 @@ func init() {
|
||||||
}
|
}
|
||||||
|
|
||||||
type State struct {
|
type State struct {
|
||||||
Position *bbgo.Position `json:"position,omitempty"`
|
Position *types.Position `json:"position,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type Target struct {
|
type Target struct {
|
||||||
|
@ -42,7 +42,7 @@ type PercentageTargetStop struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// GenerateOrders generates the orders from the given targets
|
// GenerateOrders generates the orders from the given targets
|
||||||
func (stop *PercentageTargetStop) GenerateOrders(market types.Market, pos *bbgo.Position) []types.SubmitOrder {
|
func (stop *PercentageTargetStop) GenerateOrders(market types.Market, pos *types.Position) []types.SubmitOrder {
|
||||||
var price = pos.AverageCost
|
var price = pos.AverageCost
|
||||||
var quantity = pos.Base
|
var quantity = pos.Base
|
||||||
|
|
||||||
|
@ -62,12 +62,12 @@ func (stop *PercentageTargetStop) GenerateOrders(market types.Market, pos *bbgo.
|
||||||
}
|
}
|
||||||
|
|
||||||
targetOrders = append(targetOrders, types.SubmitOrder{
|
targetOrders = append(targetOrders, types.SubmitOrder{
|
||||||
Symbol: market.Symbol,
|
Symbol: market.Symbol,
|
||||||
Market: market,
|
Market: market,
|
||||||
Type: types.OrderTypeLimit,
|
Type: types.OrderTypeLimit,
|
||||||
Side: types.SideTypeSell,
|
Side: types.SideTypeSell,
|
||||||
Price: targetPrice,
|
Price: targetPrice,
|
||||||
Quantity: targetQuantity,
|
Quantity: targetQuantity,
|
||||||
MarginSideEffect: target.MarginOrderSideEffect,
|
MarginSideEffect: target.MarginOrderSideEffect,
|
||||||
TimeInForce: "GTC",
|
TimeInForce: "GTC",
|
||||||
})
|
})
|
||||||
|
@ -178,7 +178,7 @@ func (s *Strategy) LoadState() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
if s.state.Position == nil {
|
if s.state.Position == nil {
|
||||||
s.state.Position = bbgo.NewPositionFromMarket(s.Market)
|
s.state.Position = types.NewPositionFromMarket(s.Market)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|
|
@ -41,7 +41,7 @@ func init() {
|
||||||
type State struct {
|
type State struct {
|
||||||
HedgePosition fixedpoint.Value `json:"hedgePosition"`
|
HedgePosition fixedpoint.Value `json:"hedgePosition"`
|
||||||
CoveredPosition fixedpoint.Value `json:"coveredPosition,omitempty"`
|
CoveredPosition fixedpoint.Value `json:"coveredPosition,omitempty"`
|
||||||
Position *bbgo.Position `json:"position,omitempty"`
|
Position *types.Position `json:"position,omitempty"`
|
||||||
ProfitStats ProfitStats `json:"profitStats,omitempty"`
|
ProfitStats ProfitStats `json:"profitStats,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -680,7 +680,7 @@ func (s *Strategy) LoadState() error {
|
||||||
|
|
||||||
// if position is nil, we need to allocate a new position for calculation
|
// if position is nil, we need to allocate a new position for calculation
|
||||||
if s.state.Position == nil {
|
if s.state.Position == nil {
|
||||||
s.state.Position = bbgo.NewPositionFromMarket(s.makerMarket)
|
s.state.Position = types.NewPositionFromMarket(s.makerMarket)
|
||||||
}
|
}
|
||||||
|
|
||||||
s.state.ProfitStats.Symbol = s.makerMarket.Symbol
|
s.state.ProfitStats.Symbol = s.makerMarket.Symbol
|
||||||
|
@ -794,14 +794,14 @@ func (s *Strategy) CrossRun(ctx context.Context, orderExecutionRouter bbgo.Order
|
||||||
}
|
}
|
||||||
|
|
||||||
if s.makerSession.MakerFeeRate > 0 || s.makerSession.TakerFeeRate > 0 {
|
if s.makerSession.MakerFeeRate > 0 || s.makerSession.TakerFeeRate > 0 {
|
||||||
s.state.Position.SetExchangeFeeRate(types.ExchangeName(s.MakerExchange), bbgo.ExchangeFee{
|
s.state.Position.SetExchangeFeeRate(types.ExchangeName(s.MakerExchange), types.ExchangeFee{
|
||||||
MakerFeeRate: s.makerSession.MakerFeeRate,
|
MakerFeeRate: s.makerSession.MakerFeeRate,
|
||||||
TakerFeeRate: s.makerSession.TakerFeeRate,
|
TakerFeeRate: s.makerSession.TakerFeeRate,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
if s.sourceSession.MakerFeeRate > 0 || s.sourceSession.TakerFeeRate > 0 {
|
if s.sourceSession.MakerFeeRate > 0 || s.sourceSession.TakerFeeRate > 0 {
|
||||||
s.state.Position.SetExchangeFeeRate(types.ExchangeName(s.SourceExchange), bbgo.ExchangeFee{
|
s.state.Position.SetExchangeFeeRate(types.ExchangeName(s.SourceExchange), types.ExchangeFee{
|
||||||
MakerFeeRate: s.sourceSession.MakerFeeRate,
|
MakerFeeRate: s.sourceSession.MakerFeeRate,
|
||||||
TakerFeeRate: s.sourceSession.TakerFeeRate,
|
TakerFeeRate: s.sourceSession.TakerFeeRate,
|
||||||
})
|
})
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package bbgo
|
package types
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
@ -6,7 +6,6 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/c9s/bbgo/pkg/fixedpoint"
|
"github.com/c9s/bbgo/pkg/fixedpoint"
|
||||||
"github.com/c9s/bbgo/pkg/types"
|
|
||||||
"github.com/c9s/bbgo/pkg/util"
|
"github.com/c9s/bbgo/pkg/util"
|
||||||
"github.com/slack-go/slack"
|
"github.com/slack-go/slack"
|
||||||
)
|
)
|
||||||
|
@ -21,7 +20,7 @@ type Position struct {
|
||||||
BaseCurrency string `json:"baseCurrency"`
|
BaseCurrency string `json:"baseCurrency"`
|
||||||
QuoteCurrency string `json:"quoteCurrency"`
|
QuoteCurrency string `json:"quoteCurrency"`
|
||||||
|
|
||||||
Market types.Market `json:"market"`
|
Market Market `json:"market"`
|
||||||
|
|
||||||
Base fixedpoint.Value `json:"base"`
|
Base fixedpoint.Value `json:"base"`
|
||||||
Quote fixedpoint.Value `json:"quote"`
|
Quote fixedpoint.Value `json:"quote"`
|
||||||
|
@ -31,13 +30,29 @@ type Position struct {
|
||||||
// This is used for calculating net profit
|
// This is used for calculating net profit
|
||||||
ApproximateAverageCost fixedpoint.Value `json:"approximateAverageCost"`
|
ApproximateAverageCost fixedpoint.Value `json:"approximateAverageCost"`
|
||||||
|
|
||||||
FeeRate *ExchangeFee `json:"feeRate,omitempty"`
|
FeeRate *ExchangeFee `json:"feeRate,omitempty"`
|
||||||
ExchangeFeeRates map[types.ExchangeName]ExchangeFee `json:"exchangeFeeRates"`
|
ExchangeFeeRates map[ExchangeName]ExchangeFee `json:"exchangeFeeRates"`
|
||||||
|
|
||||||
|
// Futures data fields
|
||||||
|
Isolated bool `json:"isolated"`
|
||||||
|
Leverage fixedpoint.Value `json:"leverage"`
|
||||||
|
InitialMargin fixedpoint.Value `json:"initialMargin"`
|
||||||
|
MaintMargin fixedpoint.Value `json:"maintMargin"`
|
||||||
|
OpenOrderInitialMargin fixedpoint.Value `json:"openOrderInitialMargin"`
|
||||||
|
PositionInitialMargin fixedpoint.Value `json:"positionInitialMargin"`
|
||||||
|
UnrealizedProfit fixedpoint.Value `json:"unrealizedProfit"`
|
||||||
|
EntryPrice fixedpoint.Value `json:"entryPrice"`
|
||||||
|
MaxNotional fixedpoint.Value `json:"maxNotional"`
|
||||||
|
PositionSide string `json:"positionSide"`
|
||||||
|
PositionAmt fixedpoint.Value `json:"positionAmt"`
|
||||||
|
Notional fixedpoint.Value `json:"notional"`
|
||||||
|
IsolatedWallet fixedpoint.Value `json:"isolatedWallet"`
|
||||||
|
UpdateTime int64 `json:"updateTime"`
|
||||||
|
|
||||||
sync.Mutex
|
sync.Mutex
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewPositionFromMarket(market types.Market) *Position {
|
func NewPositionFromMarket(market Market) *Position {
|
||||||
return &Position{
|
return &Position{
|
||||||
Symbol: market.Symbol,
|
Symbol: market.Symbol,
|
||||||
BaseCurrency: market.BaseCurrency,
|
BaseCurrency: market.BaseCurrency,
|
||||||
|
@ -64,9 +79,9 @@ func (p *Position) SetFeeRate(exchangeFee ExchangeFee) {
|
||||||
p.FeeRate = &exchangeFee
|
p.FeeRate = &exchangeFee
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Position) SetExchangeFeeRate(ex types.ExchangeName, exchangeFee ExchangeFee) {
|
func (p *Position) SetExchangeFeeRate(ex ExchangeName, exchangeFee ExchangeFee) {
|
||||||
if p.ExchangeFeeRates == nil {
|
if p.ExchangeFeeRates == nil {
|
||||||
p.ExchangeFeeRates = make(map[types.ExchangeName]ExchangeFee)
|
p.ExchangeFeeRates = make(map[ExchangeName]ExchangeFee)
|
||||||
}
|
}
|
||||||
|
|
||||||
p.ExchangeFeeRates[ex] = exchangeFee
|
p.ExchangeFeeRates[ex] = exchangeFee
|
||||||
|
@ -127,15 +142,15 @@ func (p *Position) String() string {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Position) BindStream(stream types.Stream) {
|
func (p *Position) BindStream(stream Stream) {
|
||||||
stream.OnTradeUpdate(func(trade types.Trade) {
|
stream.OnTradeUpdate(func(trade Trade) {
|
||||||
if p.Symbol == trade.Symbol {
|
if p.Symbol == trade.Symbol {
|
||||||
p.AddTrade(trade)
|
p.AddTrade(trade)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Position) AddTrades(trades []types.Trade) (fixedpoint.Value, fixedpoint.Value, bool) {
|
func (p *Position) AddTrades(trades []Trade) (fixedpoint.Value, fixedpoint.Value, bool) {
|
||||||
var totalProfitAmount, totalNetProfit fixedpoint.Value
|
var totalProfitAmount, totalNetProfit fixedpoint.Value
|
||||||
for _, trade := range trades {
|
for _, trade := range trades {
|
||||||
if profit, netProfit, madeProfit := p.AddTrade(trade); madeProfit {
|
if profit, netProfit, madeProfit := p.AddTrade(trade); madeProfit {
|
||||||
|
@ -147,7 +162,7 @@ func (p *Position) AddTrades(trades []types.Trade) (fixedpoint.Value, fixedpoint
|
||||||
return totalProfitAmount, totalNetProfit, totalProfitAmount != 0
|
return totalProfitAmount, totalNetProfit, totalProfitAmount != 0
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Position) AddTrade(t types.Trade) (profit fixedpoint.Value, netProfit fixedpoint.Value, madeProfit bool) {
|
func (p *Position) AddTrade(t Trade) (profit fixedpoint.Value, netProfit fixedpoint.Value, madeProfit bool) {
|
||||||
price := fixedpoint.NewFromFloat(t.Price)
|
price := fixedpoint.NewFromFloat(t.Price)
|
||||||
quantity := fixedpoint.NewFromFloat(t.Quantity)
|
quantity := fixedpoint.NewFromFloat(t.Quantity)
|
||||||
quoteQuantity := fixedpoint.NewFromFloat(t.QuoteQuantity)
|
quoteQuantity := fixedpoint.NewFromFloat(t.QuoteQuantity)
|
||||||
|
@ -189,7 +204,7 @@ func (p *Position) AddTrade(t types.Trade) (profit fixedpoint.Value, netProfit f
|
||||||
// Base < 0 means we're in short position
|
// Base < 0 means we're in short position
|
||||||
switch t.Side {
|
switch t.Side {
|
||||||
|
|
||||||
case types.SideTypeBuy:
|
case SideTypeBuy:
|
||||||
if p.Base < 0 {
|
if p.Base < 0 {
|
||||||
// convert short position to long position
|
// convert short position to long position
|
||||||
if p.Base+quantity > 0 {
|
if p.Base+quantity > 0 {
|
||||||
|
@ -217,7 +232,7 @@ func (p *Position) AddTrade(t types.Trade) (profit fixedpoint.Value, netProfit f
|
||||||
|
|
||||||
return 0, 0, false
|
return 0, 0, false
|
||||||
|
|
||||||
case types.SideTypeSell:
|
case SideTypeSell:
|
||||||
if p.Base > 0 {
|
if p.Base > 0 {
|
||||||
// convert long position to short position
|
// convert long position to short position
|
||||||
if p.Base-quantity < 0 {
|
if p.Base-quantity < 0 {
|
|
@ -1,4 +1,4 @@
|
||||||
package bbgo
|
package types
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
@ -6,7 +6,6 @@ import (
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
|
||||||
"github.com/c9s/bbgo/pkg/fixedpoint"
|
"github.com/c9s/bbgo/pkg/fixedpoint"
|
||||||
"github.com/c9s/bbgo/pkg/types"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestPosition_ExchangeFeeRate_Short(t *testing.T) {
|
func TestPosition_ExchangeFeeRate_Short(t *testing.T) {
|
||||||
|
@ -17,7 +16,7 @@ func TestPosition_ExchangeFeeRate_Short(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
feeRate := 0.075 * 0.01
|
feeRate := 0.075 * 0.01
|
||||||
pos.SetExchangeFeeRate(types.ExchangeBinance, ExchangeFee{
|
pos.SetExchangeFeeRate(ExchangeBinance, ExchangeFee{
|
||||||
MakerFeeRate: fixedpoint.NewFromFloat(feeRate),
|
MakerFeeRate: fixedpoint.NewFromFloat(feeRate),
|
||||||
TakerFeeRate: fixedpoint.NewFromFloat(feeRate),
|
TakerFeeRate: fixedpoint.NewFromFloat(feeRate),
|
||||||
})
|
})
|
||||||
|
@ -27,24 +26,24 @@ func TestPosition_ExchangeFeeRate_Short(t *testing.T) {
|
||||||
fee := quoteQuantity * feeRate
|
fee := quoteQuantity * feeRate
|
||||||
averageCost := (quoteQuantity - fee) / quantity
|
averageCost := (quoteQuantity - fee) / quantity
|
||||||
bnbPrice := 570.0
|
bnbPrice := 570.0
|
||||||
pos.AddTrade(types.Trade{
|
pos.AddTrade(Trade{
|
||||||
Exchange: types.ExchangeBinance,
|
Exchange: ExchangeBinance,
|
||||||
Price: 3000.0,
|
Price: 3000.0,
|
||||||
Quantity: quantity,
|
Quantity: quantity,
|
||||||
QuoteQuantity: quoteQuantity,
|
QuoteQuantity: quoteQuantity,
|
||||||
Symbol: "BTCUSDT",
|
Symbol: "BTCUSDT",
|
||||||
Side: types.SideTypeSell,
|
Side: SideTypeSell,
|
||||||
Fee: fee / bnbPrice,
|
Fee: fee / bnbPrice,
|
||||||
FeeCurrency: "BNB",
|
FeeCurrency: "BNB",
|
||||||
})
|
})
|
||||||
|
|
||||||
_, netProfit, madeProfit := pos.AddTrade(types.Trade{
|
_, netProfit, madeProfit := pos.AddTrade(Trade{
|
||||||
Exchange: types.ExchangeBinance,
|
Exchange: ExchangeBinance,
|
||||||
Price: 2000.0,
|
Price: 2000.0,
|
||||||
Quantity: 10.0,
|
Quantity: 10.0,
|
||||||
QuoteQuantity: 2000.0 * 10.0,
|
QuoteQuantity: 2000.0 * 10.0,
|
||||||
Symbol: "BTCUSDT",
|
Symbol: "BTCUSDT",
|
||||||
Side: types.SideTypeBuy,
|
Side: SideTypeBuy,
|
||||||
Fee: 2000.0 * 10.0 * feeRate / bnbPrice,
|
Fee: 2000.0 * 10.0 * feeRate / bnbPrice,
|
||||||
FeeCurrency: "BNB",
|
FeeCurrency: "BNB",
|
||||||
})
|
})
|
||||||
|
@ -62,7 +61,7 @@ func TestPosition_ExchangeFeeRate_Long(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
feeRate := 0.075 * 0.01
|
feeRate := 0.075 * 0.01
|
||||||
pos.SetExchangeFeeRate(types.ExchangeBinance, ExchangeFee{
|
pos.SetExchangeFeeRate(ExchangeBinance, ExchangeFee{
|
||||||
MakerFeeRate: fixedpoint.NewFromFloat(feeRate),
|
MakerFeeRate: fixedpoint.NewFromFloat(feeRate),
|
||||||
TakerFeeRate: fixedpoint.NewFromFloat(feeRate),
|
TakerFeeRate: fixedpoint.NewFromFloat(feeRate),
|
||||||
})
|
})
|
||||||
|
@ -72,24 +71,24 @@ func TestPosition_ExchangeFeeRate_Long(t *testing.T) {
|
||||||
fee := quoteQuantity * feeRate
|
fee := quoteQuantity * feeRate
|
||||||
averageCost := (quoteQuantity + fee) / quantity
|
averageCost := (quoteQuantity + fee) / quantity
|
||||||
bnbPrice := 570.0
|
bnbPrice := 570.0
|
||||||
pos.AddTrade(types.Trade{
|
pos.AddTrade(Trade{
|
||||||
Exchange: types.ExchangeBinance,
|
Exchange: ExchangeBinance,
|
||||||
Price: 3000.0,
|
Price: 3000.0,
|
||||||
Quantity: quantity,
|
Quantity: quantity,
|
||||||
QuoteQuantity: quoteQuantity,
|
QuoteQuantity: quoteQuantity,
|
||||||
Symbol: "BTCUSDT",
|
Symbol: "BTCUSDT",
|
||||||
Side: types.SideTypeBuy,
|
Side: SideTypeBuy,
|
||||||
Fee: fee / bnbPrice,
|
Fee: fee / bnbPrice,
|
||||||
FeeCurrency: "BNB",
|
FeeCurrency: "BNB",
|
||||||
})
|
})
|
||||||
|
|
||||||
_, netProfit, madeProfit := pos.AddTrade(types.Trade{
|
_, netProfit, madeProfit := pos.AddTrade(Trade{
|
||||||
Exchange: types.ExchangeBinance,
|
Exchange: ExchangeBinance,
|
||||||
Price: 4000.0,
|
Price: 4000.0,
|
||||||
Quantity: 10.0,
|
Quantity: 10.0,
|
||||||
QuoteQuantity: 4000.0 * 10.0,
|
QuoteQuantity: 4000.0 * 10.0,
|
||||||
Symbol: "BTCUSDT",
|
Symbol: "BTCUSDT",
|
||||||
Side: types.SideTypeSell,
|
Side: SideTypeSell,
|
||||||
Fee: 4000.0 * 10.0 * feeRate / bnbPrice,
|
Fee: 4000.0 * 10.0 * feeRate / bnbPrice,
|
||||||
FeeCurrency: "BNB",
|
FeeCurrency: "BNB",
|
||||||
})
|
})
|
||||||
|
@ -103,7 +102,7 @@ func TestPosition(t *testing.T) {
|
||||||
var feeRate = 0.05 * 0.01
|
var feeRate = 0.05 * 0.01
|
||||||
var testcases = []struct {
|
var testcases = []struct {
|
||||||
name string
|
name string
|
||||||
trades []types.Trade
|
trades []Trade
|
||||||
expectedAverageCost fixedpoint.Value
|
expectedAverageCost fixedpoint.Value
|
||||||
expectedBase fixedpoint.Value
|
expectedBase fixedpoint.Value
|
||||||
expectedQuote fixedpoint.Value
|
expectedQuote fixedpoint.Value
|
||||||
|
@ -111,9 +110,9 @@ func TestPosition(t *testing.T) {
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "base fee",
|
name: "base fee",
|
||||||
trades: []types.Trade{
|
trades: []Trade{
|
||||||
{
|
{
|
||||||
Side: types.SideTypeBuy,
|
Side: SideTypeBuy,
|
||||||
Price: 1000.0,
|
Price: 1000.0,
|
||||||
Quantity: 0.01,
|
Quantity: 0.01,
|
||||||
QuoteQuantity: 1000.0 * 0.01,
|
QuoteQuantity: 1000.0 * 0.01,
|
||||||
|
@ -128,9 +127,9 @@ func TestPosition(t *testing.T) {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "quote fee",
|
name: "quote fee",
|
||||||
trades: []types.Trade{
|
trades: []Trade{
|
||||||
{
|
{
|
||||||
Side: types.SideTypeSell,
|
Side: SideTypeSell,
|
||||||
Price: 1000.0,
|
Price: 1000.0,
|
||||||
Quantity: 0.01,
|
Quantity: 0.01,
|
||||||
QuoteQuantity: 1000.0 * 0.01,
|
QuoteQuantity: 1000.0 * 0.01,
|
||||||
|
@ -145,15 +144,15 @@ func TestPosition(t *testing.T) {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "long",
|
name: "long",
|
||||||
trades: []types.Trade{
|
trades: []Trade{
|
||||||
{
|
{
|
||||||
Side: types.SideTypeBuy,
|
Side: SideTypeBuy,
|
||||||
Price: 1000.0,
|
Price: 1000.0,
|
||||||
Quantity: 0.01,
|
Quantity: 0.01,
|
||||||
QuoteQuantity: 1000.0 * 0.01,
|
QuoteQuantity: 1000.0 * 0.01,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Side: types.SideTypeBuy,
|
Side: SideTypeBuy,
|
||||||
Price: 2000.0,
|
Price: 2000.0,
|
||||||
Quantity: 0.03,
|
Quantity: 0.03,
|
||||||
QuoteQuantity: 2000.0 * 0.03,
|
QuoteQuantity: 2000.0 * 0.03,
|
||||||
|
@ -167,21 +166,21 @@ func TestPosition(t *testing.T) {
|
||||||
|
|
||||||
{
|
{
|
||||||
name: "long and sell",
|
name: "long and sell",
|
||||||
trades: []types.Trade{
|
trades: []Trade{
|
||||||
{
|
{
|
||||||
Side: types.SideTypeBuy,
|
Side: SideTypeBuy,
|
||||||
Price: 1000.0,
|
Price: 1000.0,
|
||||||
Quantity: 0.01,
|
Quantity: 0.01,
|
||||||
QuoteQuantity: 1000.0 * 0.01,
|
QuoteQuantity: 1000.0 * 0.01,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Side: types.SideTypeBuy,
|
Side: SideTypeBuy,
|
||||||
Price: 2000.0,
|
Price: 2000.0,
|
||||||
Quantity: 0.03,
|
Quantity: 0.03,
|
||||||
QuoteQuantity: 2000.0 * 0.03,
|
QuoteQuantity: 2000.0 * 0.03,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Side: types.SideTypeSell,
|
Side: SideTypeSell,
|
||||||
Price: 3000.0,
|
Price: 3000.0,
|
||||||
Quantity: 0.01,
|
Quantity: 0.01,
|
||||||
QuoteQuantity: 3000.0 * 0.01,
|
QuoteQuantity: 3000.0 * 0.01,
|
||||||
|
@ -195,21 +194,21 @@ func TestPosition(t *testing.T) {
|
||||||
|
|
||||||
{
|
{
|
||||||
name: "long and sell to short",
|
name: "long and sell to short",
|
||||||
trades: []types.Trade{
|
trades: []Trade{
|
||||||
{
|
{
|
||||||
Side: types.SideTypeBuy,
|
Side: SideTypeBuy,
|
||||||
Price: 1000.0,
|
Price: 1000.0,
|
||||||
Quantity: 0.01,
|
Quantity: 0.01,
|
||||||
QuoteQuantity: 1000.0 * 0.01,
|
QuoteQuantity: 1000.0 * 0.01,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Side: types.SideTypeBuy,
|
Side: SideTypeBuy,
|
||||||
Price: 2000.0,
|
Price: 2000.0,
|
||||||
Quantity: 0.03,
|
Quantity: 0.03,
|
||||||
QuoteQuantity: 2000.0 * 0.03,
|
QuoteQuantity: 2000.0 * 0.03,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Side: types.SideTypeSell,
|
Side: SideTypeSell,
|
||||||
Price: 3000.0,
|
Price: 3000.0,
|
||||||
Quantity: 0.10,
|
Quantity: 0.10,
|
||||||
QuoteQuantity: 3000.0 * 0.10,
|
QuoteQuantity: 3000.0 * 0.10,
|
||||||
|
@ -224,15 +223,15 @@ func TestPosition(t *testing.T) {
|
||||||
|
|
||||||
{
|
{
|
||||||
name: "short",
|
name: "short",
|
||||||
trades: []types.Trade{
|
trades: []Trade{
|
||||||
{
|
{
|
||||||
Side: types.SideTypeSell,
|
Side: SideTypeSell,
|
||||||
Price: 2000.0,
|
Price: 2000.0,
|
||||||
Quantity: 0.01,
|
Quantity: 0.01,
|
||||||
QuoteQuantity: 2000.0 * 0.01,
|
QuoteQuantity: 2000.0 * 0.01,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Side: types.SideTypeSell,
|
Side: SideTypeSell,
|
||||||
Price: 3000.0,
|
Price: 3000.0,
|
||||||
Quantity: 0.03,
|
Quantity: 0.03,
|
||||||
QuoteQuantity: 3000.0 * 0.03,
|
QuoteQuantity: 3000.0 * 0.03,
|
Loading…
Reference in New Issue
Block a user