Skip to content

Commit

Permalink
fix(backtesting): fix profits and trade results (#243)
Browse files Browse the repository at this point in the history
  • Loading branch information
rodrigo-brito authored Mar 25, 2023
1 parent ec6792c commit e3a1d47
Show file tree
Hide file tree
Showing 4 changed files with 43 additions and 55 deletions.
39 changes: 8 additions & 31 deletions examples/strategies/emacross.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,45 +54,22 @@ func (e *CrossEMA) OnCandle(df *ninjabot.Dataframe, broker service.Broker) {
return
}

if (quotePosition > 10 || assetPosition*closePrice < -10) && df.Metadata["ema8"].Crossover(df.Metadata["sma21"]) {
if assetPosition < 0 {
// close previous short position
_, err := broker.CreateOrderMarket(ninjabot.SideTypeBuy, df.Pair, -assetPosition)
if err != nil {
log.Error(err)
}
if quotePosition >= 10 && // minimum quote position to trade
df.Metadata["ema8"].Crossover(df.Metadata["sma21"]) { // trade signal (EMA8 > SMA21)

assetPosition, quotePosition, err = broker.Position(df.Pair)
if err != nil {
log.Error(err)
return
}
}

_, err = broker.CreateOrderMarket(ninjabot.SideTypeBuy, df.Pair, quotePosition/closePrice*0.99)
amount := quotePosition / closePrice // calculate amount of asset to buy
_, err := broker.CreateOrderMarket(ninjabot.SideTypeBuy, df.Pair, amount)
if err != nil {
log.Error(err)
}

return
}

if (assetPosition*closePrice > 10 || quotePosition > 10) &&
df.Metadata["ema8"].Crossunder(df.Metadata["sma21"]) {
if assetPosition > 0 {
// close previous long position
_, err := broker.CreateOrderMarket(ninjabot.SideTypeSell, df.Pair, assetPosition)
if err != nil {
log.Error(err)
}

assetPosition, quotePosition, err = broker.Position(df.Pair)
if err != nil {
log.Error(err)
return
}
}
if assetPosition > 0 &&
df.Metadata["ema8"].Crossunder(df.Metadata["sma21"]) { // trade signal (EMA8 < SMA21)

_, err = broker.CreateOrderMarket(ninjabot.SideTypeSell, df.Pair, quotePosition/closePrice*0.99)
_, err = broker.CreateOrderMarket(ninjabot.SideTypeSell, df.Pair, assetPosition)
if err != nil {
log.Error(err)
}
Expand Down
16 changes: 16 additions & 0 deletions exchange/paperwallet.go
Original file line number Diff line number Diff line change
Expand Up @@ -505,6 +505,10 @@ func (p *PaperWallet) CreateOrderOCO(side model.SideType, pair string,
p.Lock()
defer p.Unlock()

if size == 0 {
return nil, ErrInvalidQuantity
}

err := p.validateFunds(side, pair, size, price, false)
if err != nil {
return nil, err
Expand Down Expand Up @@ -550,6 +554,10 @@ func (p *PaperWallet) CreateOrderLimit(side model.SideType, pair string,
p.Lock()
defer p.Unlock()

if size == 0 {
return model.Order{}, ErrInvalidQuantity
}

err := p.validateFunds(side, pair, size, limit, false)
if err != nil {
return model.Order{}, err
Expand Down Expand Up @@ -580,6 +588,10 @@ func (p *PaperWallet) CreateOrderStop(pair string, size float64, limit float64)
p.Lock()
defer p.Unlock()

if size == 0 {
return model.Order{}, ErrInvalidQuantity
}

err := p.validateFunds(model.SideTypeSell, pair, size, limit, false)
if err != nil {
return model.Order{}, err
Expand All @@ -602,6 +614,10 @@ func (p *PaperWallet) CreateOrderStop(pair string, size float64, limit float64)
}

func (p *PaperWallet) createOrderMarket(side model.SideType, pair string, size float64) (model.Order, error) {
if size == 0 {
return model.Order{}, ErrInvalidQuantity
}

err := p.validateFunds(side, pair, size, p.lastCandle[pair].Close, true)
if err != nil {
return model.Order{}, err
Expand Down
9 changes: 3 additions & 6 deletions order/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -246,19 +246,16 @@ func (c *Controller) processTrade(order *model.Order) {
// register order volume
c.Results[order.Pair].Volume += order.Price * order.Quantity

// calculate profit only to sell orders
if order.Side != model.SideTypeSell {
return
}

profitValue, profit, err := c.calculateProfit(order)
if err != nil {
c.notifyError(err)
return
}

order.Profit = profit
if profitValue >= 0 {
if profitValue == 0 {
return
} else if profitValue > 0 {
if order.Side == model.SideTypeBuy {
c.Results[order.Pair].WinLong = append(c.Results[order.Pair].WinLong, profitValue)
} else {
Expand Down
34 changes: 16 additions & 18 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
[![Discord](https://img.shields.io/discord/960156400376483840?color=5865F2&label=discord)](https://discord.gg/TGCrUH972E)
[![Discord](https://img.shields.io/badge/donate-patreon-red)](https://www.patreon.com/ninjabot_github)

A fast cryptocurrency trading bot framework implemented in Go. Ninjabot permits users to create and test custom strategies for spot markets.
A fast cryptocurrency trading bot framework implemented in Go. Ninjabot permits users to create and test custom strategies for sport and future markets.

Docs: https://rodrigo-brito.github.io/ninjabot/

Expand Down Expand Up @@ -49,36 +49,35 @@ go run examples/backtesting/main.go
Output:

```
INFO[2022-10-16 16:34] [SETUP] Using paper wallet
INFO[2022-10-16 16:34] [SETUP] Initial Portfolio = 10000.000000 USDT
+---------+--------+-----+------+--------+--------+-----+----------+-----------+
INFO[2023-03-25 13:54] [SETUP] Using paper wallet
INFO[2023-03-25 13:54] [SETUP] Initial Portfolio = 10000.000000 USDT
---------+--------+-----+------+--------+--------+-----+----------+-----------+
| PAIR | TRADES | WIN | LOSS | % WIN | PAYOFF | SQN | PROFIT | VOLUME |
+---------+--------+-----+------+--------+--------+-----+----------+-----------+
| BTCUSDT | 14 | 6 | 8 | 42.9 % | 5.929 | 1.5 | 13511.66 | 448030.04 |
| ETHUSDT | 9 | 6 | 3 | 66.7 % | 3.407 | 1.3 | 21748.41 | 407769.64 |
| BTCUSDT | 14 | 6 | 8 | 42.9 % | 5.929 | 1.5 | 13511.66 | 448030.05 |
+---------+--------+-----+------+--------+--------+-----+----------+-----------+
| TOTAL | 23 | 12 | 11 | 52.2 % | 4.942 | 1.4 | 35260.07 | 855799.68 |
+---------+--------+-----+------+--------+--------+-----+----------+-----------+
-- FINAL WALLET --
0.0000 BTC = 0.0000 USDT
0.0000 ETH = 0.0000 USDT
45260.0734 USDT
45260.0735 USDT
----- RETURNS -----
START PORTFOLIO = 10000.00 USDT
FINAL PORTFOLIO = 45260.07 USDT
GROSS PROFIT = 35260.073380 USDT (352.60%)
GROSS PROFIT = 35260.073493 USDT (352.60%)
MARKET CHANGE (B&H) = 407.09%
------ RISK -------
MAX DRAWDOWN = -11.76 %
------ VOLUME -----
BTCUSDT = 448030.05 USDT
ETHUSDT = 407769.64 USDT
BTCUSDT = 448030.04 USDT
TOTAL = 855799.68 USDT
COSTS (0.001*V) = 855.80 USDT (ESTIMATION)
-------------------
Chart available at http://localhost:8080
Expand All @@ -90,14 +89,14 @@ Chart available at http://localhost:8080

### Features

| | Binance Spot | Binance Futures |
|-------------------- |-------------- |---------------- |
| Order Market | :ok: | :ok: |
| Order Market Quote | :ok: | |
| Order Limit | :ok: | :ok: |
| Order Stop | :ok: | :ok: |
| Order OCO | :ok: | |
| Backtesting | :ok: | :construction: |
| | Binance Spot | Binance Futures |
|-------------------- |-------------- |-------------------|
| Order Market | :ok: | :ok: |
| Order Market Quote | :ok: | |
| Order Limit | :ok: | :ok: |
| Order Stop | :ok: | :ok: |
| Order OCO | :ok: | |
| Backtesting | :ok: | :ok: |

- [x] Backtesting
- [x] Paper Wallet (Live Trading with fake wallet)
Expand All @@ -115,7 +114,6 @@ Chart available at http://localhost:8080
# Roadmap
- [ ] Include Web UI Controller
- [ ] Include more chart indicators - [Details](https://github.com/rodrigo-brito/ninjabot/issues/110)
- [ ] Support future market - [Details](https://github.com/rodrigo-brito/ninjabot/issues/106)

### Exchanges

Expand Down

0 comments on commit e3a1d47

Please sign in to comment.