Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

InvalidOrder: Not enough base currency. Available: 0.02037. hold: 0. requested: 0.02038. #159

Closed
rohsat opened this issue Apr 23, 2022 · 3 comments

Comments

@rohsat
Copy link

rohsat commented Apr 23, 2022

Description

I was backtesting my custom logic (exchange=Binance) but I keep getting the below error frequently. I have seen this error in the example code also. It works fine for some of resolution/duration. It seems to be a floating point/rounding/truncate issue.

Could you please take a look?

Error

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/rs/Desktop/ML/GitHub/blankly/examples/rolling_window_breakout.py", line 84, in price_event
    interface.market_order(symbol, 'sell', state.interface.account[state.base_asset].available)
  File "/Users/rs/Desktop/ML/GitHub/blankly/blankly/exchanges/interfaces/paper_trade/paper_trade_interface.py", line 391, in market_order
    self.local_account.test_trade(symbol, side, qty, price, market_limits['market_order']["quote_increment"],
  File "/Users/rs/Desktop/ML/GitHub/blankly/blankly/exchanges/interfaces/paper_trade/local_account/trade_local.py", line 192, in test_trade
    raise InvalidOrder("Not enough base currency. Available: " +
blankly.utils.exceptions.InvalidOrder: Not enough base currency. Available: 0.02037. hold: 0. requested: 0.02038.

Code

import blankly
from blankly import Strategy, StrategyState, Interface
from blankly import Binance
from blankly.indicators import sma
#import math

my_stop_loss = 0
my_target = 0

my_winning_trades =0
my_losing_trades = 0

my_stop_loss_percent = 1
my_target_percent = 1.5


def init(symbol, state: StrategyState):
    interface: Interface = state.interface
    resolution = state.resolution
    variables = state.variables
    # initialize the historical data
    variables['history'] = interface.history(symbol, 25, resolution, end_date=state.time, return_as='deque')['close']
    variables['owns_position'] = False


def price_event(price, symbol, state: StrategyState):
    interface: Interface = state.interface
    variables = state.variables
    window_max_price = max(variables['history'])
    window_min_price = min(variables['history'])

    action = 'Hold'
    global my_stop_loss
    global my_target
    global my_winning_trades
    global my_losing_trades

    if window_max_price > price > window_min_price:
        action = 'Hold'

    elif price > window_max_price:
        action = 'Buy'

    elif price < window_min_price:
        action = 'Sell'

    # trailing stoploss and target

    if my_stop_loss < price*(100-my_stop_loss_percent)/100:
        my_stop_loss = price*(100-my_stop_loss_percent)/100
        my_target = my_target+ 0.5 * price*(my_target_percent) / 100


    #print(f'{action} --- price:{price},    max:{window_max_price},    min:{window_min_price}')
    variables['history'].append(price)

    # comparing prev diff with current  diff will show a cross
    if action == 'Buy' and not variables['owns_position']:
        interface.market_order(symbol, 'buy', blankly.trunc(interface.cash / price, 5))
        variables['owns_position'] = True
        my_stop_loss = price * (100-my_stop_loss_percent)/100
        my_target = price * (100+my_target_percent)/100
        print(f'My Buy:{price}')
    # Stop Loss Handling
    # elif price < my_stop_loss and variables['owns_position']:
    #     interface.market_order(symbol, 'sell', state.interface.account[state.base_asset].available)
    #     variables['owns_position'] = False
    #     my_stop_loss = 0


    #elif action == 'Sell' and variables['owns_position']:
    elif (price > my_target or price < my_stop_loss) and variables['owns_position']:
        if(price < my_stop_loss):
            print(f'SL Hit:{price}  Target{my_target}   SL {my_stop_loss}')
            my_losing_trades +=1
        elif (price > my_target):
            my_winning_trades +=1
            print(f'Target Hit:{price}  Target{my_target}   SL {my_stop_loss}')
        # use strategy.base_asset if on CoinbasePro or Binance
        # interface.market_order(symbol, 'sell', int(interface.account[symbol].available))
        interface.market_order(symbol, 'sell', state.interface.account[state.base_asset].available)

        variables['owns_position'] = False
        my_stop_loss = 0
        my_target = 0

    # sma200 = sma(variables['history'], period=200)
    # # match up dimensions
    # sma50 = sma(variables['history'], period=50)[-len(sma200):]
    # diff = sma200 - sma50
    # slope_sma50 = (sma50[-1] - sma50[-5]) / 5  # get the slope of the last 5 SMA50 Data Points
    # prev_diff = diff[-2]
    # curr_diff = diff[-1]
    # is_cross_up = slope_sma50 > 0 and curr_diff >= 0 and prev_diff < 0
    # is_cross_down = slope_sma50 < 0 and curr_diff <= 0 and prev_diff > 0
    #
    # # comparing prev diff with current  diff will show a cross
    # if is_cross_up and not variables['owns_position']:
    #     interface.market_order(symbol, 'buy', blankly.trunc(interface.cash/price,5))
    #     variables['owns_position'] = True
    # elif is_cross_down and variables['owns_position']:
    #     # use strategy.base_asset if on CoinbasePro or Binance
    #     # interface.market_order(symbol, 'sell', int(interface.account[symbol].available))
    #     interface.market_order(symbol, 'sell', state.interface.account[state.base_asset].available)

    #     variables['owns_position'] = False

if __name__ == "__main__":
    ex = Binance()
    s = Strategy(ex)
    s.add_price_event(price_event, 'BTC-USDT', resolution='30m', init=init)
    # s.add_price_event(price_event, 'GME', resolution='1h', init=init)
    results = s.backtest(initial_values={'USDT': 1000}, to='3mo')
    print(results)
    print(f'Win Count:{my_winning_trades}, Loss Count:{my_losing_trades}')
    # Or just run it directly on the exchange
    # s.start()

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
  }
}

Platform Info

  • Python version: 3.10
  • Platform: MacOS (M1)

Additional context
Add any other context about the problem here.

@EmersonDove
Copy link
Member

Nice catch, this is a known bug but I've never been able to track down where the rounding error happens. I would recommend for now using blankly.trunc to round one more decimal on your account value.

@EmersonDove
Copy link
Member

Hey I just ran your code and I can't seem to replicate your error. I'm using python 3.7 but I also couldn't replicate it in a Docker image running python 3.10 (intel Mac).

@AlphonsG
Copy link

AlphonsG commented Dec 19, 2023

Back-testing bitcoin from 2022-5-1 to 2023-12-1 with an initial amount of 100000 USDT on KuCoin produced this error. Increasing the initial amount to 10000000000 eliminated it. @EmersonDove

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants