separate net profit and profit

This commit is contained in:
c9s 2021-05-22 17:17:37 +08:00
parent 20f02886de
commit cca3284140
4 changed files with 30 additions and 22 deletions

View File

@ -107,18 +107,19 @@ func (p *Position) BindStream(stream types.Stream) {
})
}
func (p *Position) AddTrades(trades []types.Trade) (fixedpoint.Value, bool) {
var totalProfitAmount fixedpoint.Value
func (p *Position) AddTrades(trades []types.Trade) (fixedpoint.Value, fixedpoint.Value, bool) {
var totalProfitAmount, totalNetProfit fixedpoint.Value
for _, trade := range trades {
if profitAmount, profit := p.AddTrade(trade); profit {
totalProfitAmount += profitAmount
if profit, netProfit, madeProfit := p.AddTrade(trade); madeProfit {
totalProfitAmount += profit
totalNetProfit += netProfit
}
}
return totalProfitAmount, totalProfitAmount != 0
return totalProfitAmount, totalNetProfit, totalProfitAmount != 0
}
func (p *Position) AddTrade(t types.Trade) (fixedpoint.Value, bool) {
func (p *Position) AddTrade(t types.Trade) (profit fixedpoint.Value, netProfit fixedpoint.Value, madeProfit bool) {
price := fixedpoint.NewFromFloat(t.Price)
quantity := fixedpoint.NewFromFloat(t.Quantity)
quoteQuantity := fixedpoint.NewFromFloat(t.QuoteQuantity)
@ -158,16 +159,19 @@ func (p *Position) AddTrade(t types.Trade) (fixedpoint.Value, bool) {
if p.Base < 0 {
// handling short-to-long position
if p.Base+quantity > 0 {
closingProfit := (p.AverageCost - price).Mul(-p.Base) - quoteFee
profit = (p.AverageCost - price).Mul(-p.Base)
netProfit = profit - quoteFee
p.Base += quantity
p.Quote -= quoteQuantity
p.AverageCost = price
return closingProfit, true
return profit, netProfit, true
} else {
// covering short position
p.Base += quantity
p.Quote -= quoteQuantity
return (p.AverageCost - price).Mul(quantity) - quoteFee, true
profit = (p.AverageCost - price).Mul(quantity)
netProfit = profit - quoteFee
return profit, netProfit, true
}
}
@ -175,21 +179,24 @@ func (p *Position) AddTrade(t types.Trade) (fixedpoint.Value, bool) {
p.Base += quantity
p.Quote -= quoteQuantity
return 0, false
return 0, 0, false
case types.SideTypeSell:
if p.Base > 0 {
// long-to-short
if p.Base-quantity < 0 {
closingProfit := (price - p.AverageCost).Mul(p.Base) - quoteFee
profit = (price - p.AverageCost).Mul(p.Base)
netProfit = profit - quoteFee
p.Base -= quantity
p.Quote += quoteQuantity
p.AverageCost = price
return closingProfit, true
return profit, netProfit, true
} else {
p.Base -= quantity
p.Quote += quoteQuantity
return (price - p.AverageCost).Mul(quantity) - quoteFee, true
profit = (price - p.AverageCost).Mul(quantity)
netProfit = profit - quoteFee
return profit, netProfit, true
}
}
@ -198,8 +205,8 @@ func (p *Position) AddTrade(t types.Trade) (fixedpoint.Value, bool) {
p.Base -= quantity
p.Quote += quoteQuantity
return 0, false
return 0, 0, false
}
return 0, false
return 0, 0, false
}

View File

@ -38,7 +38,7 @@ func TestPosition_ExchangeFeeRate_Short(t *testing.T) {
FeeCurrency: "BNB",
})
profit, madeProfit := pos.AddTrade(types.Trade{
profit, _, madeProfit := pos.AddTrade(types.Trade{
Exchange: types.ExchangeBinance,
Price: 2000.0,
Quantity: 10.0,
@ -83,7 +83,7 @@ func TestPosition_ExchangeFeeRate_Long(t *testing.T) {
FeeCurrency: "BNB",
})
profit, madeProfit := pos.AddTrade(types.Trade{
profit, _, madeProfit := pos.AddTrade(types.Trade{
Exchange: types.ExchangeBinance,
Price: 4000.0,
Quantity: 10.0,
@ -253,7 +253,7 @@ func TestPosition(t *testing.T) {
BaseCurrency: "BTC",
QuoteCurrency: "USDT",
}
profitAmount, profit := pos.AddTrades(testcase.trades)
profitAmount, _, profit := pos.AddTrades(testcase.trades)
assert.Equal(t, testcase.expectedQuote, pos.Quote, "expectedQuote")
assert.Equal(t, testcase.expectedBase, pos.Base, "expectedBase")

View File

@ -391,9 +391,9 @@ func (s *Strategy) tradeUpdateHandler(trade types.Trade) {
return
}
profit, madeProfit := s.state.Position.AddTrade(trade)
profit, netProfit, madeProfit := s.state.Position.AddTrade(trade)
if madeProfit {
s.Notify("average cost profit: %f", profit.Float64())
s.Notify("%s average cost profit: %f, net profit =~ %f", s.Symbol, profit.Float64(), netProfit.Float64())
}
}
}

View File

@ -536,7 +536,7 @@ func (s *Strategy) handleTradeUpdate(trade types.Trade) {
s.state.HedgePosition.AtomicAdd(q)
s.state.AccumulatedVolume.AtomicAdd(fixedpoint.NewFromFloat(trade.Quantity))
if profit, madeProfit := s.state.Position.AddTrade(trade); madeProfit {
if profit, netProfit, madeProfit := s.state.Position.AddTrade(trade); madeProfit {
s.state.AccumulatedPnL.AtomicAdd(profit)
if profit < 0 {
@ -552,11 +552,12 @@ func (s *Strategy) handleTradeUpdate(trade types.Trade) {
since = time.Unix(s.state.AccumulatedSince, 0).In(localTimeZone)
}
s.Notify("%s trade profit %s %f %s (%.3f%%), since %s accumulated net profit %f %s, accumulated loss %f %s",
s.Notify("%s trade profit %s %f %s (%.3f%%), net profit =~ %f %s, since %s accumulated net profit %f %s, accumulated loss %f %s",
s.Symbol,
pnlEmoji(profit),
profit.Float64(), s.state.Position.QuoteCurrency,
profitMargin.Float64()*100.0,
netProfit.Float64(), s.state.Position.QuoteCurrency,
since.Format(time.RFC822),
s.state.AccumulatedPnL.Float64(), s.state.Position.QuoteCurrency,
s.state.AccumulatedLoss.Float64(), s.state.Position.QuoteCurrency)