Skip to content
All strategies

Strategies

je-suis-tm Shooting Star, causal port on a point-in-time US large-cap panel: confirmed eight-condition shooting star -> short at next open, exit on a +/-5% close move or after 7 sessions (VOD.USEQ + S&P 500 members as of each bar, 1-DAY, short-only, next-session-open fills)

Outcome: Verifying

PanelCausalShootingStarShort

je-suis-tm Shooting Star, causal port on a point-in-time US large-cap panel: confirmed eight-condition shooting star -> short at next open, exit on a +/-5% close move or after 7 sessions (VOD.USEQ + S&P 500 members as…

Hypothesis

Port of 'Shooting Star backtest' by je-suis-tm (quant-trading, Apache-2.0, commit 611b73f). The rules and default parameters below are the author's. Any performance the source implies is unverified; our backtest with real costs decides. The source's Investopedia link (S2) could not be fetched (HTTP 402), so only the code (S1) was read. Source rules: a shooting star is a bar where (1) Open >= Close; (2) Close - Low < lower_bound * |Close - Open| (little or no lower wick); (3) |Open - Close| < body_size * reference……Show moreShow less

Port of 'Shooting Star backtest' by je-suis-tm (quant-trading, Apache-2.0, commit 611b73f). The rules and default parameters below are the author's. Any performance the source implies is unverified; our backtest with real costs decides. The source's Investopedia link (S2) could not be fetched (HTTP 402), so only the code (S1) was read. Source rules: a shooting star is a bar where (1) Open >= Close; (2) Close - Low < lower_bound * |Close - Open| (little or no lower wick); (3) |Open - Close| < body_size * reference body (small body); (4) High - Open >= 2 * (Open - Close) (upper wick at least 2x the body); (5) Close >= previous Close and (6) previous Close >= the Close before it (uptrend); (7) the NEXT bar's High <= the star's High and (8) the NEXT bar's Close <= the star's Close. The trade is a short. It exits when |Close / entry - 1| > stop_threshold (0.05, the same rule takes profit and stops loss) or after holding_period = 7 bars. Defaults: lower_bound 0.2, body_size 0.5, stop_threshold 0.05, holding_period 7. WHY THIS VERSION: the previous attempt ran the conjunction on VOD.USEQ alone and produced no trades in the sandbox (1,401 sessions). A firing-rate check, which measures feasibility and says nothing about performance, shows why. Across all of VOD.USEQ's 9,557 daily bars the confirmed signal holds only about 6 times. On 25 long-lived US large caps since 2005 it holds about 0.044 times per name-year. The binding conditions are 1+2+5 together (a red candle that closes at its low after a gap up), not the body size: relaxing body_size from 0.5 to 2.0 only lifts the rate to 0.063. Any single US name gives about one trade per 20 years. CHANGES, each labelled: (A) UNIVERSE: we keep the user's market, Vodafone on its US listing, VOD.USEQ (VOD.L/UKEQ is not enabled on this platform). VOD.USEQ is the primary instrument and is always eligible. The identical rule also runs independently on every S&P 500 member AS OF EACH BAR (self.index_member(iid, 'sp500') / universe_at(index='sp500'), former members included where bars exist, parameters['point_in_time_universe']=True; extra_instruments = `python -m src.data.listings sp500 --start 1996-01-01 --end <run end> --with-data`). That gives about 20-25 signals per year. This is the only way to test the source's exact pattern definition with a usable sample, and it avoids survivorship bias. (B) CAUSALITY: conditions 7 and 8 use the next bar, and the source books the short at the star's own close (look-ahead). Here the star is bar t-1. Bar t is the confirmation bar: High_t <= High_{t-1} and Close_t <= Close_{t-1}. The short is decided at the close of bar t and fills at the NEXT session's open (next_open_fill, supported on USEQ). (C) BODY REFERENCE (condition 3): the source compares against abs(np.mean(Open - Close)) over the WHOLE dataset. That uses future data, and because the signed mean is near zero, condition 3 almost never holds. Here the reference is the mean of |Open - Close| over the previous body_lookback = 20 sessions of the same name, excluding the star bar. This follows the author's own comment that the body test should be relaxed. (D) BOOKKEEPING: one net short per name. A new star on a name already short is ignored. Overlapping signals in the source's signal column are not reproduced. (E) EXIT REFERENCE: the +/-5% test uses the actual fill price as entry; the source used the star's close. Exits are tested on daily CLOSES, as written, not intrabar. The exit is decided at the close and fills at the next session's open. (F) SIZING (platform default; the source has none): each short is 10% of current equity in notional, whole shares, at most 10 open shorts. Gross short exposure is therefore at most 100% of equity on the 2x Reg-T margin account. If more than the free slots signal on one day, take them in ascending ticker order, so selection never uses performance. Risk control route (b): signal exits (the +/-5% close rule plus a 7-session time limit) with capped sizing. Losing 5% plus an overnight gap on a 10% position costs about 0.5-1% of equity. Zero commissions; spread and impact are modelled about 1 bp per side. Dividends are not in PnL, which slightly flatters shorts (stated as a risk).

Retry after no_trades: the source's conjunction holds about 6 times in 38 years on VOD itself. Running the identical rule across a point-in-time S&P 500 panel, with VOD kept as primary, gives a testable sample without changing the pattern. USEQ short-only daily is also under-represented (USEQ 9.7%, long_short/short 24%).

Implementation

Causal port of je-suis-tm's eight-condition shooting star, run independently on VOD.USEQ (always eligible) and every S&P 500 member as of each bar (1-DAY USEQ). Star = bar t-1; bar t confirms (High_t<=High_{t-1}, Close_t<=Close_{t-1}); short decided at the close of t, filled at the next session open. Exit when |close/fill-1|>5% or after 7 sessions, decided on the close and filled at the next open. 10% of equity per short, whole shares, at most 10 open shorts, ties taken in ascending ticker order.

Implements hypothesis v2 changes A-F: (A) VOD.USEQ primary plus 741 point-in-time S&P 500 legs (src.data.listings sp500 1996-2026 --with-data), filtered by index_member/is_listed on every bar, point_in_time_universe=True; (B) condition 7/8 moved to a confirmation bar, next-open fill (next_open_fill supported); (C) body reference = mean |O-C| over the previous body_lookback=20 sessions excluding the star, kept as a running sum; (D) one net short per name, new stars on held names ignored; (E) +/-5% test against the actual fill price on daily closes; (F) 10% equity notional per short, max 10, so gross short <=100% of equity, risk route (b). Per-name candle state is updated in on_extra_bar from each leg's own bars; the alignment barrier guarantees all listed legs' same-session bars are in before the VOD bar drives the decision, and only legs whose last bar timestamp equals the primary session are used. The previous code ran VOD alone (expanding signed mean), which the hypothesis now replaces.

Verification Results

Verification failed (Layer 3 — sandbox backtest): No trades produced Bar type used: VOD.USEQ-1-DAY-LAST-EXTERNAL, Bars processed: 1401 Diagnostics: should_enter() returned a side 0 times over 1401 evaluated bars -> your ENTRY CONDITION never triggered. Loosen the entry logic / thresholds. Ensure your strategy produces trades with the given data and parameters.

Analysis

Shooting Star backtest

Analysis

Shooting%20Star%20backtest.py

Backtest and paper results are hypothetical. Trading involves risk of loss.