edtechre / pybroker

Algorithmic Trading in Python with Machine Learning
https://www.pybroker.com
Other
2.09k stars 261 forks source link

Error: Fill price 0 for prices below 0.005$ (like many cryptocurrencies) #89

Closed SW4T400 closed 11 months ago

SW4T400 commented 11 months ago

Hi Ed,

I am getting the following error when the close price goes below 0.005$ for any of my symbols - I assume that some rounding occurs somewhere.

  File \src\pybroker\portfolio.py:395 in _verify_input
    raise ValueError(f"Fill price must be > 0: {fill_price} ")

ValueError: Fill price must be > 0: 0.0 

To confirm this I first ran BTCUSDT with its real price > 4000$ in the date range I use and then devided the price by 1_000_000 to turn 5000 => 0.005 for a second run. On the second run the backtesting fails EXACTLY on the first candle that has a price below 0.005 (the image shows the original price): image

I have reproduced this for a couple of cryptocurrencies and it always happens at the first 1-3 candles below closing price 0.005. Its not always exactly the first candle with close price below the threshold, but thats probably because fills are done on the "mid" price and not the close. image

This is a potential issue for alot of cryptocurrencies that might be valued far below 1$ or any pairs that use BTC (or any highly valued asset) as quote currency. I had chosen 7 crypto pairs at random for developing a "charting/plotting solution" and 5/7 were below 0.005$

Info: I am using this rule:

def buy_low_test(ctx):
    if ctx.long_pos():
        return
    if ctx.bars >= 2 and ctx.close[-1] < ctx.low[-2]:
        ctx.buy_shares = ctx.calc_target_shares(0.25)
        ctx.buy_limit_price = ctx.close[-1]
        ctx.hold_bars = 3
edtechre commented 11 months ago

Thanks for reporting @SW4T400,

I think this is due to PriceType.MIDDLE being the default fill type, and it rounds to the nearest cent by default.

I will add a config option to allow disabling the rounding behavior.

In the meantime, you can specify another fill price type: ctx.buy_fill_price = PriceType.CLOSE

SW4T400 commented 11 months ago

Thank you for the info. For now I have changed this line to remove the round function and it seems to do the trick.

Old:  round((low[-1] + (high[-1] - low[-1]) / 2.0), 2)
New: (low[-1] + (high[-1] - low[-1]) / 2.0)
edtechre commented 11 months ago

I committed a new round_fill_price config option to the dev branch. Setting it to False will disable this behavior.

Targeted for v1.1.31