blankly-finance / blankly

🚀 💸 Easily build, backtest and deploy your algo in just a few lines of code. Trade stocks, cryptos, and forex across exchanges w/ one package.
https://package.blankly.finance
GNU Lesser General Public License v3.0
2.11k stars 267 forks source link

Binance: Issue in Golden Cross example #158

Closed rohsat closed 2 years ago

rohsat commented 2 years ago

Description

While backtesting golden_cross.py example in BInance with asset = BTC-USTD, the code was able buy but not sell.

The code only worked when I modified the below line (as given in rsi.py).

        interface.market_order(symbol, 'sell', int(interface.account[symbol].available))

to

        interface.market_order(symbol, 'sell', state.interface.account[state.base_asset].available)

Could you please check why this is happening?

settings.json

{
  "settings": {
    "use_sandbox_websockets": false,
    "websocket_buffer_size": 10000,
    "test_connectivity_on_auth": true,

    "coinbase_pro": {
      "cash": "USD"
    },
    "binance": {
      "cash": "USDT",
      "binance_tld": "com"
    },
    "alpaca": {
      "websocket_stream": "iex",
      "cash": "USD",
      "enable_shorting": true,
      "use_yfinance": false
    },
    "oanda": {
      "cash": "USD"
    },
    "keyless": {
      "cash": "USD"
    },
    "kucoin": {
      "cash": "USDT"
    },
    "ftx": {
      "cash": "USD"
    }
  }
}

backtest.json

{
  "price_data": {
    "assets": []
  },
  "settings": {
    "use_price": "close",
    "smooth_prices": false,
    "GUI_output": true,
    "show_tickers_with_zero_delta": false,
    "save_initial_account_value": true,
    "show_progress_during_backtest": true,
    "cache_location": "./price_caches",
    "continuous_caching": true,
    "resample_account_value_for_metrics": "1d",
    "quote_account_value_in": "USDT",
    "ignore_user_exceptions": true,
    "risk_free_return_rate": 0.0,
    "benchmark_symbol" : null
  }
}

Error (got the error multiple times - showing two)

Progress: [#####-----] 47.6% Traceback (most recent call last):
  File "/Users/rohitsathyanathan/Desktop/ML/GitHub/blankly/blankly/exchanges/interfaces/paper_trade/backtest_controller.py", line 771, in run
    self.price_events[0]['function'](self.interface.get_price(self.price_events[0]['asset_id']),
  File "/Users/rs/Desktop/ML/GitHub/blankly/examples/golden_cross.py", line 40, in price_event
    interface.market_order(symbol, 'sell', int(interface.account[symbol].available))
KeyError: 'BTC-USDT'

Progress: [######----] 55.89% Traceback (most recent call last):
  File "/Users/rs/Desktop/ML/GitHub/blankly/blankly/exchanges/interfaces/paper_trade/backtest_controller.py", line 771, in run
    self.price_events[0]['function'](self.interface.get_price(self.price_events[0]['asset_id']),
  File "/Users/rohitsathyanathan/Desktop/ML/GitHub/blankly/examples/golden_cross.py", line 40, in price_event
    interface.market_order(symbol, 'sell', int(interface.account[symbol].available))
KeyError: 'BTC-USDT'
Progress: [##########] 100% Done...

Platform Info

bfan1256 commented 2 years ago

Hey @rohsat, this is indeed correct and we highlight this a little bit in here. The issue is because when you store the asset, the asset is stored as BTC and not stored as BTC-USDT, as a result, we do have to store it and utilize the interface.account[state.base_asset].available . You can also take a look at this sample RSI that's found here


def price_event(price, symbol, state: blankly.StrategyState):
    """ This function will give an updated price every 15 seconds from our definition below """
    state.variables['history'].append(price)
    rsi = blankly.indicators.rsi(state.variables['history'])
    if rsi[-1] < 40 and not state.variables['owns_position']:
        # Dollar cost average buy
        buy = blankly.trunc(state.interface.cash/price, 2)
        state.interface.market_order(symbol, side='buy', size=buy)
        state.variables['owns_position'] = True
    elif rsi[-1] > 60 and state.variables['owns_position']:
        # Dollar cost average sell
        curr_value = blankly.trunc(state.interface.account[state.base_asset].available, 2)
        state.interface.market_order(symbol, side='sell', size=curr_value)
        state.variables['owns_position'] = False

def init(symbol, state: blankly.StrategyState):
    # Download price data to give context to the algo
    state.variables['history'] = state.interface.history(symbol, to=150, return_as='deque',
                                                         resolution=state.resolution)['close']
    state.variables['owns_position'] = False