Comments (5)
The ADVSTEX generator a strict exit generator and has no logic to manipulate entries - those have to be prepared and provided by the user.
There are several options you can go: the first one is creation of a custom entry & exit generator (as you did apparently) with a custom entry function that does some basic order management and ADVSTEX exit function, the second one is filtering entries beforehand using signals accessor (but this assumes that your entries do not depend upon previous exits).
If you can elaborate more on limit entry orders (are those stop entry orders that are canceled once a stop is reached or simple buy stops?) and provide me with an example on how you currently handle them, I can help integrating a more general version of it into the package.
from vectorbt.
Sorry for the delayed response. I wanted to work on this issue as soon as your reply but was caught up in other aspects. To answer your question, this issue relates to simple limit buy orders.
Implementing a limit buy order has a few considerations:
- The limit price may never hit, and thus the limit order never filled;
- If the limit order never fills and the signal changes, the unfilled order is stale and should be canceled.
- [Open ended] How long should a limit buy stay open before cancelling?
I wrote a simple example to implement in my system that fulfils the above considerations by running the assumption (on point 3) that consecutive signals belong to the same "signal session", and therefore unfilled limit orders are stale and should be canceled if they are left unfilled when the signal changes.
It seems though that a time-based expiry setting for limit orders are the convention so you may factor that into your development. "Signal session" style works for me, with the side benefit that the possibility of overtrading of the same signal won't happen in this style.
import numpy as np
import pandas as pd
index = pd.date_range('1/1/2000', periods=20, freq='T')
d = {
'Signal': np.random.randint(2, size=20),
'Limit Entry Price': np.random.uniform(8, 9, size=20),
'Close': np.random.uniform(8.4, 8.6, size=20),
}
bt_df = pd.DataFrame(d, index=index)
# Make Limit Entry Prices persist across consecutive rows where Signals are True
# We must cancel unfilled orders if Signal changes in live
bt_df.loc[(bt_df['Signal'].shift() == bt_df['Signal']), 'Limit Entry Price'] = np.nan
bt_df['Limit Entry Price'] = bt_df['Limit Entry Price'].ffill()
bt_df.loc[bt_df['Signal'] == 0, 'Limit Entry Price'] = np.nan
bt_df['Limit Entry'] = False
bt_df.loc[(bt_df['Signal'] == True) & (bt_df['Limit Entry Price'] > bt_df['Close']), 'Limit Entry'] = True
bt_df.loc[(bt_df['Limit Entry'].shift() == bt_df['Limit Entry']) & (bt_df['Limit Entry'] == True), 'Limit Entry'] = False
print(bt_df)
# I then run ADVSTEX to get stop exits
# advstex = vbt.ADVSTEX.run(
# bt_df['Limit Entry'], bt_df['Open'], bt_df['High'], bt_df['Low'], bt_df['Close'],
# hit_price=bt_df['Limit Entry Price'],
# sl_stop=sl_stops, tp_stop=tp_stops,
# param_product=True
# )
# Result
Signal Limit Entry Price Close Limit Entry
2000-01-01 00:00:00 0 NaN 8.564140 False
2000-01-01 00:01:00 0 NaN 8.520179 False
2000-01-01 00:02:00 1 8.757558 8.470297 True
2000-01-01 00:03:00 0 NaN 8.412795 False
2000-01-01 00:04:00 1 8.238643 8.505277 False
2000-01-01 00:05:00 0 NaN 8.404852 False
2000-01-01 00:06:00 1 8.022066 8.498470 False
2000-01-01 00:07:00 0 NaN 8.471920 False
2000-01-01 00:08:00 1 8.226325 8.438089 False
2000-01-01 00:09:00 1 8.226325 8.439872 False
2000-01-01 00:10:00 1 8.226325 8.502265 False
2000-01-01 00:11:00 1 8.226325 8.501408 False
2000-01-01 00:12:00 1 8.226325 8.517973 False
2000-01-01 00:13:00 1 8.226325 8.421095 False
2000-01-01 00:14:00 0 NaN 8.446641 False
2000-01-01 00:15:00 1 8.584325 8.502960 True
2000-01-01 00:16:00 1 8.584325 8.560458 False
2000-01-01 00:17:00 1 8.584325 8.451963 False
2000-01-01 00:18:00 0 NaN 8.534686 False
2000-01-01 00:19:00 0 NaN 8.410393 False
On a side note, I saw that shorting function has been added to portfolio. Hope that ADVSTEX (and signals modules) will include support for it!
from vectorbt.
Buy limit orders can be done in multiple ways in vectorbt, but all of them involve setting relative stops in percentage terms because vectorbt puts focus on hyperparameter optimization. For example, 1% stop:
entry_signals = bt_df['Signal'].astype(bool)\
.vbt.signals.first()\
.vbt.signals.generate_stop_exits(bt_df['Close'], -0.01, exit_wait=0)
Here we use generate_stop_exits
to generate entries, those can then be fed to 1) ADVSTEX that preserves your entries and tries to find exits for each of them, or 2) IADVSTEX that tries to fill the first entry order -> if filled, finds an exit -> if found, finds the next entry order after that exit -> etc..
A better approach in your case would involve working directly with Portfolio.from_order_func
that processes timestamps one by one (streaming approach), so you can define your own order management logic there, instead of relying upon multiple layers of signal generation that can expose you to look-ahead bias, etc. I personally use signal generators only for analyzing the distribution of signals and other data analyses, while backtesting is done iteratively.
from vectorbt.
I do use relative stops in percentages so that isn't a problem for me.
That's a novel solution to generate entries (using generate_stop_exits
). I think I can use it. Can you explain a bit what vbt.signals.first()
does?
Regarding generate_stop_exits
, does the entry_wait
parameter imply that there is no need to manually shift the prices/signals to avoid look-ahead bias?
from vectorbt.
vbt.signals.first
selects the first True out of a series of consecutive True values. There is also a possibility to select the first True out of a series delimited by another boolean array (reset_by
argument).
The only drawback of generate_stop_exits
: it doesn't fill the hit price, so you need to do it yourself by using forward fill. The more advanced method that takes OHLC generate_adv_stop_exits
also fills the hit price and the type of a stop being hit (as you can define multiple stop types at different timestamps).
Regarding exit_wait
: vectorbt uses an approach, where for each entry signal, it defines a range after it and searches an exit signal within this range. exit_wait
defines where this range starts. exit_wait = 0
means you can start searching for exit signals from the same bar as the entry. Normally, exit_wait
is 1 because vectorbt allows only placing one order at a timestamp, but I used 0 just to be consistent with your example.
from vectorbt.
Related Issues (20)
- Open short position right after closing long position with full capital HOT 3
- Installing vectorbt on Google Colab HOT 1
- plot with 1m granularity takes forever HOT 5
- portfolio.from_signals reporting HIGH variations with fees vs no fees
- set sl/tp to be triggered on exact values
- Portfolio.stats consumes large amount of memory. HOT 1
- Need to add requirement: nbformat>=4.2.0
- Vectorbt documentation code examples throws unsupported error. HOT 1
- Assertion Error with VectorBT Portfolio from MultiIndex DataFrame
- Reverse position with from_signals HOT 1
- tp_stop with accumulate gives wrong result
- Data mismatch
- Incorrect Position Size Allocation Across Multiple Assets HOT 3
- For the same precision data, there is an accuracy error in the results.
- Issues with combining multiple plots into subplots in 1 figure HOT 1
- Plotting Error: Subplot 'trade_pnl' raised an exception HOT 1
- Getting Daily PNL Portfolio Change
- What is the difference in the documentation of vectorbt PRO vs the open source vectorbt?
- What is the benchmark plotted in pf.plot().show()?
- How to use run_combs in combination with other signals?
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from vectorbt.