polakowo / vectorbt

Find your trading edge, using the fastest engine for backtesting, algorithmic trading, and research.
https://vectorbt.dev
Other
4.42k stars 622 forks source link

Multiple entries before Exit #140

Closed ben1628 closed 3 years ago

ben1628 commented 3 years ago

I was using C# to do my actual trading/backtesting with some success.

My strategies are like this.

My Buy order shares are like 100,90,70,70,50 in that order.

1/ When my entry is true, I will buy 100, then if my exit is true, I will sell 100 shares. 2/ when my entry is true, I will buy 100, if the entry is still true on the next signal, I will buy another 90. Now I have 190 shares on hand, then if my exit becomes true, I will sell 90; if entry is true after that, I will buy back the 90.

Can Vectorbt handles something like this? of course, my program is event driven and so it can handle it but backtest DO take sometimes, although not long.

Reason I like vectorbt is I can do multiple parameters and find out which one is the best.

polakowo commented 3 years ago

Of course, you just need to get familiar with from_order_func. But be aware that writing such logic in vectorbt is much more difficult than using other backtesters, you need to be at least intermediate in numpy. And please try not to create an issue for each question you have; documentation is your best friend.

ben1628 commented 3 years ago

I tried not to, but that is the question I have ever since I start using your solution. Can you provide me with some guidelines to help me? On average, it takes me 30 minutes to run the whole years to run the above situation, and if I change any parameter, it will take another 30 minutes to find out whether it's good or not.

I thought I could read through the documentation to get some ideas, but found it difficult to do so.

polakowo commented 3 years ago

Your strategy is simple enough to avoid using Portfolio.from_order_func, you may just need to build a size array and use Portfolio.from_orders. For this, you need to create a function that takes entries and exits (as NumPy arrays) and outputs an array with how much you want to buy (positive number) or sell (negative number). If you don't want to buy or sell at any time step, the element should be np.nan. First, write this function as a regular Python function. Then, wrap it with @njit decorator to speed it up with Numba. Then pass it as size argument to Portfolio.from_orders. For example:

import numpy as np
import pandas as pd
import vectorbt as vbt
from numba import njit

price = pd.Series([1, 2, 3, 4])
entries = pd.Series([True, True, False, False])
exits = pd.Series([False, False, True, True])

@njit
def signals_to_size(entries, exits):
    size = np.full(entries.shape, np.nan, np.float64)
    shares_now = 0
    for i in range(entries.shape[0]):
        if entries[i]:
            if shares_now == 0:
                size[i] = 100
            elif shares_now == 100:
                size[i] = 90
            else:
                pass # write other conditions
        elif exits[i]:
            if shares_now == 100:
                size[i] = -100
            elif shares_now == 190:
                size[i] = -90
            else:
                pass # write other conditions
        if not np.isnan(size[i]):
            shares_now += size[i]
    return size

size = signals_to_size(entries.values, exits.values)
print(size)
[ 100.   90.  -90. -100.]

portfolio = vbt.Portfolio.from_orders(price, size)
print(portfolio.total_return())
2.1

This is very much simplified but should be enough for getting started.

ben1628 commented 3 years ago

Thanks for your help