edtechre / pybroker

Algorithmic Trading in Python with Machine Learning

Home Page:https://www.pybroker.com

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

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

SW4T400 opened this issue · comments

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

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

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)

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