Imports required by the code examples below
Expanding trade metrics¶
- Regular metrics such as MAE and MFE represent only the final point of each trade, but what if we would like to see their development during each trade? You can now analyze expanding trade metrics as DataFrames!
Visualize the expanding MFE using projections
- New method for plotting trades that categorizes entry and exit trades into long entries, long exits, short entries, and short exits. Supports different styles for positions.
Plot trade signals of a Bollinger Bands strategy
>>> data = vbt.YFData.pull("BTC-USD") >>> bb = data.run("bbands") >>> entries = data.hlc3.vbt.crossed_above(bb.upper) & (bb.bandwidth < 0.1) >>> exits = data.hlc3.vbt.crossed_below(bb.upper) & (bb.bandwidth > 0.5) >>> short_entries = data.hlc3.vbt.crossed_below(bb.lower) & (bb.bandwidth < 0.1) >>> short_exits = data.hlc3.vbt.crossed_above(bb.lower) & (bb.bandwidth > 0.5) >>> pf = vbt.PF.from_signals(data, entries, exits, short_entries, short_exits) >>> pf.plot_trade_signals().show()
- Edge ratio is a unique way to quantify entry profitability. Unlike most performance metrics, the edge ratio takes both open profits and losses into account. This can help you determine optimal trade exits.
Compare the edge ratio of an EMA crossover to a random strategy
>>> data = vbt.YFData.pull("BTC-USD") >>> fast_ema = data.run("ema", 10, hide_params=True) >>> slow_ema = data.run("ema", 20, hide_params=True) >>> entries = fast_ema.real_crossed_above(slow_ema) >>> exits = fast_ema.real_crossed_below(slow_ema) >>> pf = vbt.PF.from_signals(data, entries, exits, direction="both") >>> rand_pf = vbt.PF.from_random_signals(data, n=pf.orders.count() // 2) # (1)! >>> fig = pf.trades.plot_running_edge_ratio( ... trace_kwargs=dict(line_color="limegreen", name="Edge Ratio (S)") ... ) >>> fig = rand_pf.trades.plot_running_edge_ratio( ... trace_kwargs=dict(line_color="mediumslateblue", name="Edge Ratio (R)"), ... fig=fig ... ) >>> fig.show()
- Random strategy should have a similar number of orders to be comparable
- Trade history is a human-readable DataFrame that lists orders and extends them with valuable information on entry trades, exit trades, and positions.
Get the trade history of a random portfolio with one signal
>>> data = vbt.YFData.pull(["BTC-USD", "ETH-USD"], missing_index="drop") >>> pf = vbt.PF.from_random_signals( ... data, ... n=1, ... run_kwargs=dict(hide_params=True), ... tp_stop=0.5, ... sl_stop=0.1 ... ) >>> pf.trade_history Order Id Column Signal Index Creation Index \ 0 0 BTC-USD 2016-02-20 00:00:00+00:00 2016-02-20 00:00:00+00:00 1 1 BTC-USD 2016-02-20 00:00:00+00:00 2016-06-12 00:00:00+00:00 2 0 ETH-USD 2019-05-25 00:00:00+00:00 2019-05-25 00:00:00+00:00 3 1 ETH-USD 2019-05-25 00:00:00+00:00 2019-07-15 00:00:00+00:00 Fill Index Side Type Stop Type Size Price \ 0 2016-02-20 00:00:00+00:00 Buy Market None 0.228747 437.164001 1 2016-06-12 00:00:00+00:00 Sell Market TP 0.228747 655.746002 2 2019-05-25 00:00:00+00:00 Buy Market None 0.397204 251.759872 3 2019-07-15 00:00:00+00:00 Sell Market SL 0.397204 226.583885 Fees PnL Return Direction Status Entry Trade Id Exit Trade Id \ 0 0.0 50.0 0.5 Long Closed 0 -1 1 0.0 50.0 0.5 Long Closed -1 0 2 0.0 -10.0 -0.1 Long Closed 0 -1 3 0.0 -10.0 -0.1 Long Closed -1 0 Position Id 0 0 1 0 2 0 3 0
- Patterns are the distinctive formations created by the movements of security prices on a chart and are the foundation of technical analysis. There are new designated functions and classes for detecting patterns of any complexity in any time series data. The concept is simple: fit a pattern to match the scale and period of the selected data window, and compute their element-wise distance to each other to derive a single similarity score. You can then tweak the threshold for this score above which a data window should be marked as "matched". Thanks to Numba, this operation can be done hundreds of thousands of times per second!
Learn more in the Patterns and projections tutorial.
Find and plot a descending triangle pattern
- There are more clean ways of analyzing events and their impact on the price than conventional backtesting. Meet projections! Not only they can allow you to assess the performance of events visually and quantitatively, but they also can enable you to project events into the future for assistance in trading. That is possible by extracting the price range after each event, putting all the price ranges into a multidimensional array, and deriving the confidence intervals and other meaningful statistics from that array. Combined with patterns, these are a quantitative analyst's dream tools!
Learn more in the Patterns and projections tutorial.
Find occurrences of the price moving similarly to the last week and project them
>>> data = vbt.YFData.pull("ETH-USD") >>> pattern_ranges = data.hlc3.vbt.find_pattern( ... pattern=data.close.iloc[-7:], ... rescale_mode="rebase" ... ) >>> delta_ranges = pattern_ranges.with_delta(7) >>> fig = data.iloc[-7:].plot(plot_volume=False) >>> delta_ranges.plot_projections(fig=fig) >>> fig.show()
MAE and MFE¶
- Maximum Adverse Excursion (MAE) helps you to identify what the maximum loss was during a trade. This is also known as maximum drawdown of the position. Maximum Favorable Excursion (MFE), on the other hand, shows you what the highest profit was during a trade. Analyzing MAE and MFE statistics can help you optimize your exit strategies.
Analyze the MAE of a random portfolio without SL
Analyze the MAE of a random portfolio with SL
- Previously, OHLC was used for simulation but only the close price was used for analysis purposes. With this update, most classes will allow you to keep track of the entire OHLC data for a more accurate quantitative and qualitative analysis.
Plot trades of a random portfolio
- Benchmark can be easily set for the entire portfolio.
Compare Microsoft to S&P 500