mirror of
https://github.com/c9s/bbgo.git
synced 2024-11-10 01:01:56 +00:00
add accumulated profit column to position
This commit is contained in:
parent
cc4ef327d6
commit
3c376b3cd3
|
@ -64,6 +64,8 @@ func (s *PositionService) Insert(position *types.Position, trade types.Trade, pr
|
|||
quote,
|
||||
profit,
|
||||
trade_id,
|
||||
exchange,
|
||||
side,
|
||||
traded_at
|
||||
) VALUES (
|
||||
:strategy,
|
||||
|
@ -76,17 +78,24 @@ func (s *PositionService) Insert(position *types.Position, trade types.Trade, pr
|
|||
:quote,
|
||||
:profit,
|
||||
:trade_id,
|
||||
:exchange,
|
||||
:side,
|
||||
:traded_at
|
||||
)`,
|
||||
map[string]interface{} {
|
||||
"strategy": "",
|
||||
"strategy_instance_id": "",
|
||||
map[string]interface{}{
|
||||
"strategy": position.Strategy,
|
||||
"strategy_instance_id": position.StrategyInstanceID,
|
||||
"symbol": position.Symbol,
|
||||
"quote_currency": position.QuoteCurrency,
|
||||
"base_currency": position.BaseCurrency,
|
||||
"average_cost": position.AverageCost,
|
||||
"base": position.Base,
|
||||
"quote": position.Quote,
|
||||
"profit": profit,
|
||||
"trade_id": trade.ID,
|
||||
"exchange": trade.Exchange,
|
||||
"side": trade.Side,
|
||||
"traded_at": trade.Time,
|
||||
})
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -17,18 +17,45 @@ func TestPositionService(t *testing.T) {
|
|||
t.Fatal(err)
|
||||
}
|
||||
|
||||
defer db.Close()
|
||||
defer func() {
|
||||
err := db.Close()
|
||||
assert.NoError(t, err)
|
||||
}()
|
||||
|
||||
xdb := sqlx.NewDb(db.DB, "sqlite3")
|
||||
service := &PositionService{DB: xdb}
|
||||
|
||||
t.Run("minimal fields", func(t *testing.T) {
|
||||
err = service.Insert(&types.Position{
|
||||
Symbol: "BTCUSDT",
|
||||
BaseCurrency: "BTC",
|
||||
QuoteCurrency: "USDT",
|
||||
AverageCost: fixedpoint.NewFromFloat(44000),
|
||||
ChangedAt: time.Now(),
|
||||
}, types.Trade{}, fixedpoint.NewFromFloat(10.9))
|
||||
}, types.Trade{
|
||||
Time: types.Time(time.Now()),
|
||||
}, 0)
|
||||
assert.NoError(t, err)
|
||||
})
|
||||
|
||||
t.Run("full fields", func(t *testing.T) {
|
||||
err = service.Insert(&types.Position{
|
||||
Symbol: "BTCUSDT",
|
||||
BaseCurrency: "BTC",
|
||||
QuoteCurrency: "USDT",
|
||||
AverageCost: fixedpoint.NewFromFloat(44000),
|
||||
Base: fixedpoint.NewFromFloat(0.1),
|
||||
Quote: fixedpoint.NewFromFloat(-44000.0),
|
||||
ChangedAt: time.Now(),
|
||||
Strategy: "bollmaker",
|
||||
StrategyInstanceID: "bollmaker-BTCUSDT-1m",
|
||||
}, types.Trade{
|
||||
ID: 9,
|
||||
Exchange: types.ExchangeBinance,
|
||||
Side: types.SideTypeSell,
|
||||
Time: types.Time(time.Now()),
|
||||
}, fixedpoint.NewFromFloat(10.9))
|
||||
assert.NoError(t, err)
|
||||
})
|
||||
|
||||
}
|
||||
|
|
|
@ -30,15 +30,15 @@ type PositionRisk struct {
|
|||
}
|
||||
|
||||
type Position struct {
|
||||
Symbol string `json:"symbol"`
|
||||
BaseCurrency string `json:"baseCurrency"`
|
||||
QuoteCurrency string `json:"quoteCurrency"`
|
||||
Symbol string `json:"symbol" db:"symbol"`
|
||||
BaseCurrency string `json:"baseCurrency" db:"base"`
|
||||
QuoteCurrency string `json:"quoteCurrency" db:"quote"`
|
||||
|
||||
Market Market `json:"market,omitempty"`
|
||||
|
||||
Base fixedpoint.Value `json:"base"`
|
||||
Quote fixedpoint.Value `json:"quote"`
|
||||
AverageCost fixedpoint.Value `json:"averageCost"`
|
||||
Base fixedpoint.Value `json:"base" db:"base"`
|
||||
Quote fixedpoint.Value `json:"quote" db:"quote"`
|
||||
AverageCost fixedpoint.Value `json:"averageCost" db:"average_cost"`
|
||||
|
||||
// ApproximateAverageCost adds the computed fee in quote in the average cost
|
||||
// This is used for calculating net profit
|
||||
|
@ -48,13 +48,15 @@ type Position struct {
|
|||
ExchangeFeeRates map[ExchangeName]ExchangeFee `json:"exchangeFeeRates"`
|
||||
|
||||
// TotalFee stores the fee currency -> total fee quantity
|
||||
TotalFee map[string]fixedpoint.Value `json:"totalFee"`
|
||||
TotalFee map[string]fixedpoint.Value `json:"totalFee" db:"-"`
|
||||
|
||||
ChangedAt time.Time `json:"changedAt,omitempty"`
|
||||
ChangedAt time.Time `json:"changedAt,omitempty" db:"changed_at"`
|
||||
|
||||
Strategy string `json:"strategy,omitempty" db:"strategy"`
|
||||
StrategyInstanceID string `json:"strategyInstanceID,omitempty" db:"strategy_instance_id"`
|
||||
|
||||
AccumulatedProfit fixedpoint.Value `json:"accumulatedProfit,omitempty" db:"accumulated_profit"`
|
||||
|
||||
sync.Mutex
|
||||
}
|
||||
|
||||
|
@ -306,6 +308,7 @@ func (p *Position) AddTrade(td Trade) (profit fixedpoint.Value, netProfit fixedp
|
|||
fee := td.Fee
|
||||
|
||||
// calculated fee in quote (some exchange accounts may enable platform currency fee discount, like BNB)
|
||||
// convert platform fee token into USD values
|
||||
var feeInQuote fixedpoint.Value = fixedpoint.Zero
|
||||
|
||||
switch td.FeeCurrency {
|
||||
|
@ -353,6 +356,7 @@ func (p *Position) AddTrade(td Trade) (profit fixedpoint.Value, netProfit fixedp
|
|||
p.Quote = p.Quote.Sub(quoteQuantity)
|
||||
p.AverageCost = price
|
||||
p.ApproximateAverageCost = price
|
||||
p.AccumulatedProfit = p.AccumulatedProfit.Add(profit)
|
||||
return profit, netProfit, true
|
||||
} else {
|
||||
// covering short position
|
||||
|
@ -360,6 +364,7 @@ func (p *Position) AddTrade(td Trade) (profit fixedpoint.Value, netProfit fixedp
|
|||
p.Quote = p.Quote.Sub(quoteQuantity)
|
||||
profit = p.AverageCost.Sub(price).Mul(quantity)
|
||||
netProfit = p.ApproximateAverageCost.Sub(price).Mul(quantity).Sub(feeInQuote)
|
||||
p.AccumulatedProfit = p.AccumulatedProfit.Add(profit)
|
||||
return profit, netProfit, true
|
||||
}
|
||||
}
|
||||
|
@ -385,12 +390,14 @@ func (p *Position) AddTrade(td Trade) (profit fixedpoint.Value, netProfit fixedp
|
|||
p.Quote = p.Quote.Add(quoteQuantity)
|
||||
p.AverageCost = price
|
||||
p.ApproximateAverageCost = price
|
||||
p.AccumulatedProfit = p.AccumulatedProfit.Add(profit)
|
||||
return profit, netProfit, true
|
||||
} else {
|
||||
p.Base = p.Base.Sub(quantity)
|
||||
p.Quote = p.Quote.Add(quoteQuantity)
|
||||
profit = price.Sub(p.AverageCost).Mul(quantity)
|
||||
netProfit = price.Sub(p.ApproximateAverageCost).Mul(quantity).Sub(feeInQuote)
|
||||
p.AccumulatedProfit = p.AccumulatedProfit.Add(profit)
|
||||
return profit, netProfit, true
|
||||
}
|
||||
}
|
||||
|
|
|
@ -136,6 +136,7 @@ func convertFloat64ToTime(vt string, f float64) (time.Time, error) {
|
|||
return time.Time{}, fmt.Errorf("the floating point value %f is out of the timestamp range", f)
|
||||
}
|
||||
|
||||
// Time type implements the driver value for sqlite
|
||||
type Time time.Time
|
||||
|
||||
var layout = "2006-01-02 15:04:05.999Z07:00"
|
||||
|
|
Loading…
Reference in New Issue
Block a user