Hypotheses
QuantRocket 'ValueMomentumTrendCombined' (VMOT) port on USEQ daily: liquidity-screened 12-1 momentum + smoothness (positive-day count) selection, equal-weight, Q-NOV quarterly rebalance, SPY 252-day trend overlay cutting exposure 50%/100% weekly; value and F-score steps NOT portable (no point-in-time fundamentals)
Translation of QuantRocket's open-source Moonshot strategy 'ValueMomentumTrendCombined' (vmot_combined.py, Apache-2.0, credit: QuantRocket LLC; modeled on Alpha Architect's VMOT ETF). LONG-ONLY, multi-instrument US…
Strategies
- VmotMomentumTrendUseq Abandoned
Hypothesis
Translation of QuantRocket's open-source Moonshot strategy 'ValueMomentumTrendCombined' (vmot_combined.py, Apache-2.0, credit: QuantRocket LLC; modeled on Alpha Architect's VMOT ETF). LONG-ONLY, multi-instrument US equity strategy on venue USEQ, 1-DAY bars. CODE values are used where they differ from the docstring: VALUE_TOP_N_PCT=20 and MOMENTUM_TOP_N_PCT=20 (the docstring says 10). PORTABILITY, stated plainly: steps 2 (value screen: cheapest 20% by EV/EBIT, EBIT>0, Sharadar ART) and 3 (top 50% by Piotroski……Show moreShow less
Translation of QuantRocket's open-source Moonshot strategy 'ValueMomentumTrendCombined' (vmot_combined.py, Apache-2.0, credit: QuantRocket LLC; modeled on Alpha Architect's VMOT ETF). LONG-ONLY, multi-instrument US equity strategy on venue USEQ, 1-DAY bars. CODE values are used where they differ from the docstring: VALUE_TOP_N_PCT=20 and MOMENTUM_TOP_N_PCT=20 (the docstring says 10). PORTABILITY, stated plainly: steps 2 (value screen: cheapest 20% by EV/EBIT, EBIT>0, Sharadar ART) and 3 (top 50% by Piotroski F-score from 9 Sharadar fundamental components) CANNOT be translated. The factory has no point-in-time fundamentals history; Yahoo supplies prices, splits and dividends only, and src/data/yahoo_quotes.py fetches current-snapshot fundamentals for display, which would be look-ahead. Step 1b (exclude financials/ADRs/REITs) is done by construction of the fixed universe below. In the port, the momentum screen therefore ranks within the whole liquidity-screened universe, where the original ranks only within quality-value stocks. That is a material change: what is left is the momentum + trend half of VMOT, and the analyst should judge it as that. Every other rule is ported exactly. UNIVERSE (fixed, all verified present in the catalog as <SYM>.USEQ-1-DAY-LAST-EXTERNAL; non-financial, non-REIT, US-listed S&P 500 large caps, no ADRs): AAPL MSFT AMZN GOOGL META NVDA AVGO ORCL CSCO ADBE CRM INTC TXN QCOM AMD IBM ACN JNJ PFE MRK ABBV LLY UNH AMGN TMO ABT MDT BMY GILD PG KO PEP WMT COST MCD NKE HD LOW SBUX DIS CMCSA VZ T XOM CVX COP CAT DE HON GE MMM UNP UPS LMT RTX BA LIN (59 stocks), plus SPY.USEQ as the trend instrument. The original TREND_SID FIBBG000BDTBL9 is SPY; SPY is a signal only and is never traded. Primary instrument = SPY.USEQ (its bar drives the daily decision clock); the 59 stocks go in extra_instruments/extra_bar_types. RULES (per daily close t, computed on synchronized closes): (1c) avg_dollar_volume = rolling 90-bar mean of close*volume; rank descending pct across names with data (pandas rank pct, average ties); liquid = rank <= 0.60. (4) momentum = (close[t-22] - close[t-252]) / close[t-252] (NaN if close[t-252]==0 or missing); rank descending pct ONLY among liquid names; have_momentum = rank <= 0.20. (5) positive_days = count of days with close.pct_change() > 0 over the last 252 bars; rank descending pct ONLY among have_momentum names; selected = rank <= 0.50. (6) Equal weight: w_i = 1/N_selected for selected names, 0 otherwise. (7) Quarterly rebalance 'Q-NOV': the stock weights are recomputed only from the signal of the last trading day of February, May, August and November, i.e. the last value inside each Q-NOV period. They are held constant until the next such date; there is no drift rebalancing in between, because Moonshot charges turnover only on weight changes. (8-9) Trend overlay on SPY: below_zero = SPY close / SPY close[t-252] - 1 < 0; below_mavg = SPY close < SPY 252-bar SMA; n = below_zero + below_mavg. This is sampled WEEKLY ('W' = weeks ending Sunday), taking the last trading day of each week (normally Friday's close), and held through the following week. Final weight = w_i if n==0, w_i/2 if n==1, 0 if n==2; the remainder stays in cash. EXECUTION LAG (target_weights_to_positions = weights.shift()): a weight change decided at close t is executed on the next session's bar t+1 with market orders. Positions are resized only when a name's FINAL target weight changes, either at a quarterly reselection or at a weekly trend-count change. Sizing: target notional_i = final_weight_i * account equity at leverage 1.0 (USEQ margin is not used); whole shares, floor; skip orders below min notional. Fees: platform USEQ (zero commission, spread+impact modeled) replaces the original $0.005/share PerShareCommission. PERFORMANCE ENGINEERING (two recent USEQ multi-name ports died on the 300 s sandbox limit): keep per-name fixed-length deques (253 closes, 90 dollar-volumes, 252 positive-day flags with a running sum, 252 SPY closes with a running sum for the SMA). Update O(1) per bar, and do the cross-sectional ranking only once per day after all 60 bars for date t have arrived (key on the bar ts, process when the date's bar set is complete or on the SPY bar), and ONLY on rebalance/trend-sample days. Never rescan history.
Analysis
ValueMomentumTrendCombined
Backtest and paper results are hypothetical. Trading involves risk of loss.