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) { func (p *Position) AddTrades(trades []types.Trade) (fixedpoint.Value, fixedpoint.Value, bool) {
var totalProfitAmount fixedpoint.Value var totalProfitAmount, totalNetProfit fixedpoint.Value
for _, trade := range trades { for _, trade := range trades {
if profitAmount, profit := p.AddTrade(trade); profit { if profit, netProfit, madeProfit := p.AddTrade(trade); madeProfit {
totalProfitAmount += profitAmount 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) 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)
@ -158,16 +159,19 @@ func (p *Position) AddTrade(t types.Trade) (fixedpoint.Value, bool) {
if p.Base < 0 { if p.Base < 0 {
// handling short-to-long position // handling short-to-long position
if p.Base+quantity > 0 { 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.Base += quantity
p.Quote -= quoteQuantity p.Quote -= quoteQuantity
p.AverageCost = price p.AverageCost = price
return closingProfit, true return profit, netProfit, true
} else { } else {
// covering short position // covering short position
p.Base += quantity p.Base += quantity
p.Quote -= quoteQuantity 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.Base += quantity
p.Quote -= quoteQuantity p.Quote -= quoteQuantity
return 0, false return 0, 0, false
case types.SideTypeSell: case types.SideTypeSell:
if p.Base > 0 { if p.Base > 0 {
// long-to-short // long-to-short
if p.Base-quantity < 0 { 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.Base -= quantity
p.Quote += quoteQuantity p.Quote += quoteQuantity
p.AverageCost = price p.AverageCost = price
return closingProfit, true return profit, netProfit, true
} else { } else {
p.Base -= quantity p.Base -= quantity
p.Quote += quoteQuantity 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.Base -= quantity
p.Quote += quoteQuantity 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", FeeCurrency: "BNB",
}) })
profit, madeProfit := pos.AddTrade(types.Trade{ profit, _, madeProfit := pos.AddTrade(types.Trade{
Exchange: types.ExchangeBinance, Exchange: types.ExchangeBinance,
Price: 2000.0, Price: 2000.0,
Quantity: 10.0, Quantity: 10.0,
@ -83,7 +83,7 @@ func TestPosition_ExchangeFeeRate_Long(t *testing.T) {
FeeCurrency: "BNB", FeeCurrency: "BNB",
}) })
profit, madeProfit := pos.AddTrade(types.Trade{ profit, _, madeProfit := pos.AddTrade(types.Trade{
Exchange: types.ExchangeBinance, Exchange: types.ExchangeBinance,
Price: 4000.0, Price: 4000.0,
Quantity: 10.0, Quantity: 10.0,
@ -253,7 +253,7 @@ func TestPosition(t *testing.T) {
BaseCurrency: "BTC", BaseCurrency: "BTC",
QuoteCurrency: "USDT", 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.expectedQuote, pos.Quote, "expectedQuote")
assert.Equal(t, testcase.expectedBase, pos.Base, "expectedBase") assert.Equal(t, testcase.expectedBase, pos.Base, "expectedBase")

View File

@ -391,9 +391,9 @@ func (s *Strategy) tradeUpdateHandler(trade types.Trade) {
return return
} }
profit, madeProfit := s.state.Position.AddTrade(trade) profit, netProfit, madeProfit := s.state.Position.AddTrade(trade)
if madeProfit { 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.HedgePosition.AtomicAdd(q)
s.state.AccumulatedVolume.AtomicAdd(fixedpoint.NewFromFloat(trade.Quantity)) 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) s.state.AccumulatedPnL.AtomicAdd(profit)
if profit < 0 { if profit < 0 {
@ -552,11 +552,12 @@ func (s *Strategy) handleTradeUpdate(trade types.Trade) {
since = time.Unix(s.state.AccumulatedSince, 0).In(localTimeZone) 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, s.Symbol,
pnlEmoji(profit), pnlEmoji(profit),
profit.Float64(), s.state.Position.QuoteCurrency, profit.Float64(), s.state.Position.QuoteCurrency,
profitMargin.Float64()*100.0, profitMargin.Float64()*100.0,
netProfit.Float64(), s.state.Position.QuoteCurrency,
since.Format(time.RFC822), since.Format(time.RFC822),
s.state.AccumulatedPnL.Float64(), s.state.Position.QuoteCurrency, s.state.AccumulatedPnL.Float64(), s.state.Position.QuoteCurrency,
s.state.AccumulatedLoss.Float64(), s.state.Position.QuoteCurrency) s.state.AccumulatedLoss.Float64(), s.state.Position.QuoteCurrency)