Evaluating POGL Trades Against Buy-and-Hold Across Eras

Should you trade in and out of positions, or should you buy and hold? If an active strategy truly offers an edge, it shouldn’t just rely on theory—it must be backed by quantitative models evaluated across multiple decades and a diverse basket of tickers. Welcome to the Security Trading Analytics blog, where we present and backtest active position management models to let the empirical data speak for themselves.

This is the third post in a multi-part series on tracking ticker performance over multiple decades across three different regimes.  The regimes are labelled: expansion, contraction, and shock.  During an expansion regime, ticker prices are generally rising.  In contrast, contraction and shock regimes denote periods of generally declining prices.  Contraction regimes have durations of months or years, and shock regimes have durations of days or months.

  • The first post in this series presents spreadsheet-based techniques for deriving historical prices for six tickers going back as far as the early 1970s through July 31, 2026.  Then, the spreadsheet derived historical prices are deposited in a SQL Server database for downstream processing and backtesting the Proper Order Gain Lock-in (POGL) model.
  • The second post in the series examines when different era-regime pairs start and stop, and if price trends during regimes follow the pattern suggested by their name.
  • This third post reviews and compares the POGL model with a buy-and-hold investment strategy across the regimes defined and validated in the second post.  In this way, the current  post attempts to answer the question asked  at the beginning of this introduction.

The Eras and Regimes Tracked in this Post

The following table lists 21 eras defined for use in the multi-part series to which this post belongs.  Each era has an associated regime.  The eras appear in chronological order (sequence 1 through 21), along with start and end dates and durations of each era.

  • The first era is associated with the 1973 OPEC oil embargo.  
  • The fourteenth era reflects the impact of the COVID-19 pandemic.
  • The twentieth era reflects market disruptions occurring during the intensive 2026 U.S./Israel bombing of Iran.
  • The twenty-first era is open as of when the following table was compiled.  Notice the duration of this era is 3.8+ months.  This is to signify that the era was not closed when the table was compiled.  Because an open era lacks a settled conclusion, including it would distort duration-normalized metrics. Therefore, while 21 eras are itemized in the following table, only the 20 closed eras (Eras 1–20) are evaluated in this post.

Era, Title, Regime, Date Range, and Duration
EraTitleRegimeDate rangeDuration
1Oil-Shock Bear MarketContraction1972-06-01 → 1974-12-062.5 yr
2Stagflation RecoveryExpansion1974-12-07 → 1981-06-306.6 yr
3Volcker RecessionContraction1981-07-01 → 1982-08-111.1 yr
41980s ExpansionExpansion1982-08-12 → 1987-10-185.2 yr
5Black Monday & AftermathShock1987-10-19 → 1987-12-312.4 mo
6Late-80s–Pre-Dot-Com RunExpansion1988-01-01 → 1995-12-318.0 yr
7Dot-Com Build-UpExpansion1996-01-01 → 2000-03-104.2 yr
8Dot-Com BustContraction2000-03-11 → 2002-10-092.6 yr
9Credit-Fueled Bull RunExpansion2002-10-10 → 2007-10-095.0 yr
10Global Financial CrisisContraction2007-10-10 → 2009-03-091.4 yr
11Post-GFC Bull MarketExpansion2009-03-10 → 2018-09-209.5 yr
122018 Trade-War CorrectionShock2018-09-21 → 2018-12-243.1 mo
13Pre-COVID RecoveryExpansion2018-12-25 → 2020-02-191.2 yr
14COVID CrashShock2020-02-20 → 2020-03-2333 days
15COVID Recovery / Bull RunExpansion2020-03-24 → 2022-01-031.8 yr
162022 Rate-Hike Bear MarketContraction2022-01-04 → 2022-10-129.3 mo
17AI-Driven Bull RunExpansion2022-10-13 → 2025-04-012.5 yr
182025 Tariff ShockShock2025-04-02 → 2025-04-098 days
192025–26 Recovery RallyExpansion2025-04-10 → 2026-02-2710.6 mo
202026 Intensive Iran BombingShock2026-03-02 → 2026-04-0737 days
212026 Post-Bombing RecoveryExpansion2026-04-08 → 2026-07-313.8 mo+

The POGL Model Definition

The POGL model is based on a trend-following system. The implementation relies on two distinct criteria sets — one set for entering a trade and a second set for exiting a trade.

  • Entry Goal: Enter a trade when trend indicators signal a period of potential price growth.
  • Exit Goal: Exit a trade when a rising price trend reverses to close strictly below an active trailing stop floor, or when an initial position closes strictly below the maximum risk floor.

The signal for a trade entry depends on a proper order relationship between the current trading day's close price and a pair of exponential moving averages: a shorter-period EMA and a longer-period EMA. The proper order relationship requires the close price to be greater than the shorter-period EMA value, and the shorter-period EMA value to be greater than the longer-period EMA value. For the baseline implementation in this post, the short and long periods are set to 21 days (ema_21) and 63 days (ema_63), respectively.

Position entry executes on the first trading session after a buy signal (T+1). The opening price of that next session serves as the initial entry price for the trade.

At trade entry, two dynamic boundary prices are established:

  • Ratchet Base Price: Set equal to the entry open price. Multiplying this base price by 1.20 establishes the initial upper boundary target (20 percent above entry).
  • Stop Loss Price (Lower Boundary): Anchored 10 percent below the entry open price, establishing the initial risk floor for the trade.

When a trading day's close price matches or exceeds the active upper boundary target, the dynamic profit ratchet triggers:

  • The ratchet base price advances by 20 percent relative to the former base price.
  • The stop loss price (lower boundary) steps up to 10 percent below the newly advanced ratchet base price.

A trade is exited when the session close price falls strictly below the active stop loss price. This exit action functions to either lock in accumulated prior gains relative to the stepped-up stop-loss floor or cut initial trade losses once the close price drops past the 10 percent risk trigger floor used in this post.

The Backtest POGL TSQL Script

The backtest for the POGL model depends on a daily trading log and a POGL trade ledger that is populated based on POGL model rules described in the preceding section.  The following TSQL script shows how to run the model in four steps.

  • Step 1 creates a the dbo.daily_trading_log table to store the daily trade data, which consists of ticker, trade date, daily open and close values, as well as two EMA value sets.  Logid is a surrogate key for the table.
  • Step2 populates the dbo.daily_trading_log table from dbo.stockhistory_with_emas table.
  • Step 3 creates the dbo.pogl_trade_ledger table, which has a separate row for each trade based on POGL model rules.
  • Step 4 is the POGL backtest engine for populating the ledger table based on the contents of the dbo.daily_trading_log table and the POGL model rules.  This step contains a pair of nested cursors.
    • The outer ticker_cursor iterates through the six tickers tracked in this post (CAT, JPM, LLY, MSFT, NVDA, SHW).
    • The inner open price cursor iterates through the trading days to implement the POGL rules and populate the ledger table with a succession of trades.

-- step 1: initialize staging table for ticker price histories and moving averages

use securitytradinganalytics;

go

 

drop table if exists dbo.daily_trading_log;

go

 

create table dbo.daily_trading_log (

    [log_id]          int identity(1,1) not null,

    [ticker]          varchar(10)       not null,

    [trade_date]      date              not null,

    [open]            numeric(10,4)     not null,

    [close]           numeric(10,4)     not null,

    [ema_21]          numeric(10,4)     null,

    [ema_63]          numeric(10,4)     null

    constraint [PK_daily_trading_log] primary key clustered ([log_id] asc)

);

go

 

-- step 2: populate staging log from repository

insert into dbo.daily_trading_log (

    [ticker],

    [trade_date],

    [open],

    [close],

    [ema_21],

    [ema_63]

)

select

    [ticker],

    [date] as [trade_date],

    [open],

    [close],

    [ema_21],

    [ema_63]

from dbo.stockhistory_with_emas

where [ticker] in ('CAT', 'JPM', 'LLY', 'MSFT', 'NVDA', 'SHW')

order by [ticker], [date] asc;

go

 

-- step 3: initialize trade ledger target table

drop table if exists dbo.pogl_trade_ledger;

go

 

create table dbo.pogl_trade_ledger (

    [trade_id]             int identity(1,1) not null,

    [ticker]               varchar(10)       not null,

    [entry_date]           date              not null,

    [entry_price]          numeric(10,4)     not null,

    [exit_date]            date              null,

    [exit_price]           numeric(10,4)     null,

    [holding_period_bars]  int               null,

    [realized_return_pct]  numeric(10,4)     null,

    constraint [PK_pogl_trade_ledger] primary key clustered ([trade_id] asc)

);

go

 

-- step 4: execute backtest engine across six tickers

declare @ticker varchar(10);

 

declare ticker_cursor cursor local fast_forward for

    select distinct [ticker]

    from dbo.daily_trading_log

    where [ticker] in ('CAT', 'JPM', 'LLY', 'MSFT', 'NVDA', 'SHW')

    order by [ticker];

 

open ticker_cursor;

fetch next from ticker_cursor into @ticker;

 

while @@fetch_status = 0

begin

    declare @trade_active bit = 0;

    declare @entry_date date;

    declare @entry_price numeric(10,4);

    declare @stop_loss_price numeric(10,4);

    declare @ratchet_base_price numeric(10,4);

    declare @holding_bars int = 0;

 

    declare @curr_date date;

    declare @curr_open numeric(10,4);

    declare @curr_close numeric(10,4);

    declare @curr_ema21 numeric(10,4);

    declare @curr_ema63 numeric(10,4);

 

    declare @entry_signal_pending bit = 0;

 

    declare price_cursor cursor local fast_forward for

        select

            [trade_date],

            [open],

            [close],

            [ema_21],

            [ema_63]

        from dbo.daily_trading_log

        where [ticker] = @ticker

        order by [trade_date] asc;

 

    open price_cursor;

    fetch next from price_cursor into

        @curr_date, @curr_open, @curr_close, @curr_ema21, @curr_ema63;

 

    while @@fetch_status = 0

    begin

        -- 1. execute pending entry at t+1 open

        if @entry_signal_pending = 1 and @trade_active = 0

        begin

            set @trade_active = 1;

            set @entry_date = @curr_date;

            set @entry_price = @curr_open;

            set @ratchet_base_price = @curr_open;

            set @stop_loss_price = round(@curr_open * 0.90, 4);

            set @holding_bars = 1;

            set @entry_signal_pending = 0;

        end

        else if @trade_active = 1

        begin

            set @holding_bars = @holding_bars + 1;

           

            -- 2. evaluate trailing stop exit on session close

            if @curr_close < @stop_loss_price

            begin

                insert into dbo.pogl_trade_ledger (

                    [ticker],

                    [entry_date],

                    [entry_price],

                    [exit_date],

                    [exit_price],

                    [holding_period_bars],

                    [realized_return_pct]

                )

                values (

                    @ticker,

                    @entry_date,

                    @entry_price,

                    @curr_date,

                    @curr_close,

                    @holding_bars,

                    round(((@curr_close - @entry_price) / @entry_price) * 100.0, 4)

                );

 

                set @trade_active = 0;

                set @entry_date = null;

                set @entry_price = null;

                set @stop_loss_price = null;

                set @ratchet_base_price = null;

                set @holding_bars = 0;

            end

            else

            begin

                -- 3. evaluate 20% dynamic profit ratchet on session close

                if @curr_close >= round(@ratchet_base_price * 1.20, 4)

                begin

                    set @ratchet_base_price = round(@ratchet_base_price * 1.20, 4);

                    set @stop_loss_price = round(@ratchet_base_price * 0.90, 4);

                end

            end

        end

 

        -- 4. evaluate entry signal on session close

        if @trade_active = 0 and @entry_signal_pending = 0

        begin

            if @curr_ema21 > @curr_ema63 and @curr_close > @curr_ema21

            begin

                set @entry_signal_pending = 1;

            end

        end

 

        fetch next from price_cursor into

            @curr_date, @curr_open, @curr_close, @curr_ema21, @curr_ema63;

    end;

 

    close price_cursor;

    deallocate price_cursor;

 

    fetch next from ticker_cursor into @ticker;

end;

 

close ticker_cursor;

deallocate ticker_cursor;

go


Contrasting POGL Trade Performance Versus Buy-and-Hold Investing

So now you have learned about the six tickers tracked in this post from the early 1970s through July 31, 2026.  You also received an introduction to the defining properties of the POGL model as well as a TSQL script, which automates the choosing of entry and exit for a succession of trades based price action for individual tickers.  This section presents selected results and commentary that compares the POGL model to a buy-and-hold investment strategy for the six tickers tracked over the 20 evaluation eras tracked in this post.

The following screenshot compares the POGL model to a buy-and-hold strategy based  on the percent return mean for each of the six tickers individually as well as the collection of all six tickers.  These results include ticker-era pairs where POGL did not specify at least one trade.  On the other hand, the buy-and-hold strategy was in the market for all tick-era pairs  even when did not specify any trades for a ticker-era pair.  The far right column displays percentage spread values between the pogl_era_pct_return_mean column values less the bh_overall_pct_return_mean.  The spread values clearly indicate that the buy-and-hold strategy massively outperforms the POGL model for all individual tickers as well as for the set of all tickers.


JPM is widely regarded as a premiere, well-capitalized financial ticker whose price movement largely reflects broad market volatility.  Additionally, JPM returns in this post a bh_overall_pct_return_mean value of 58.42 %.  However, buy-and-hold investors with JPM shares would have experienced a bumpy ride on their way to that 58.42 % across the 20 eras tracked in this post.

The following result set shows the bh_overall_pct_return values by era for the JPM ticker.  There are a total of 7 of 20 eras with a bear market decline of 20% or more.  Furthermore, 2 of those 7 declines (-71.06% and -66.11%) could easily encourage some investors to dispose of their JPM shares at depressed prices before reaching their 58.42% for holding their shares across the 20 era set.  This is an example of one type of challenge that buy-and-hold investors must face.



This section’s last screenshot compares the POGL model to a buy-and-hold strategy based on the number of trading days during which capital was at risk.  By definition, the buy-and-hold  strategy was available for all trading days in each era.  In contrast, the POGL model had capital at risk for the duration of each trade.  If no trades were specified in an era, then no capital was at risk in that era.  On the other hand, trade accounting for the POGL model can span days from multiple eras when its entry date is in one era, but its exit date is in another era.  Basically, this second approach compares the buy-and-hold  strategy to the POGL model on how efficiently capital is used when each approach is in the market.

The buy-and-hold strategy still outperforms across the full set of all tickers, but on an individual ticker basis the POGL model has a more favorable spread for 3 of 6 tickers.  Because the POGL model returned inferior performance is 6 out of 6 individual ticker comparisons based  on the percent return mean for individual tickers, this second set of comparisons shows the POGL model more efficient at returning relatively improved performance for the JPM, MSFT, and SHW tickers.



Concluding Comments

Based on the quantitative backtest data across 20 market regimes and 374 POGL trade lifecycles, the performance metrics for the six tickers tracked over the evaluation timeframe indicate that a buy-and-hold strategy outperformed POGL, which is generally representative of other trend-following models.  However, before applying this conclusion to your own trading practice, ask whether the results reported here apply to the range of stocks you consider as investment candidates.  Traders utilizing an active trading model like POGL will likely not restrict their holdings to stocks with large market capitalizations and multi-decade resilience, such as the six tickers tracked in this post.

Choosing an appropriate sample of securities for evaluating investment strategies is a very challenging assignment.  For example, I recently read from the Ask Gemini feature in my Chrome browser that between 15 and 50 companies per year, depending on the era, are dropped from the S&P 500 index.  Therefore, it is likely that well over 100 companies out of the S&P 500 members did not survive the timeframe of the stocks included in this study.  These historical facts are presented to encourage you to carefully consider the stocks tracked in your own investment evaluation studies.

Another major consideration for investment strategy evaluation projects is on which indicators do you base your investment strategies.  The POGL model relies on a combination of exponential moving averages, close prices, dynamic stop and limit orders, and daily price action.  Some automated investment strategies have simpler mechanisms, such as just moving average crossovers, Relative Strength reversals, or MACD indicator crossovers.  To definitively determine whether a buy-and-hold investment strategy is better or worse than automated trading models generally requires considering a very wide range of models.

This blog views automated models for selecting entry and exit dates for security trades as a fruitful endeavor.  This post is our initial comparison of the POGL model versus a buy-and-hold strategy.  The POGL model can be tested with other parameters as well as against other benchmarks besides the six-ticker collection used in this post.  In the near-term future, look forward to evaluations of Heikin-Ashi candles as a basis for investment models.


Appendix A: Code for the first image in the Contrasting POGL Trade Performance Versus Buy-and-Hold Investing Section

=======================================================================
-- POGL vs. Buy-and-Hold -- Mean Pct Return by Era (aggregate/outcome view)
-- ============================================================================
-- Part 1 of a two-script pair supporting the "Contrasting POGL Trade
-- Performance Versus Buy-and-Hold Investing" post section. This script
-- answers: over a full era, which approach actually accumulated more
-- return -- the outcome a buy-and-hold investor experiences directly,
-- since buy-and-hold is continuously invested for the whole era.
--
-- Companion script: pogl_vs_bh_capital_at_risk_return.sql answers a
-- different, complementary question -- when POGL's capital was actually
-- deployed, how did its rate of return compare to buy-and-hold's? See
-- that script's header for why the two questions need separate treatment.
--
-- POPULATION: every eligible era for each ticker, INCLUDING eras where
-- POGL never entered a position (credited with a flat 0% return, since it
-- held cash). This is deliberate -- it's what makes the outcome-level
-- comparison honest: buy-and-hold does not get to skip a bad era, so
-- POGL's zero-trade eras must stay in the average too, not be dropped as
-- if they never happened.
--
-- Same table sources and exclusions as prior scripts in this series:
--   dbo.market_regime_ledger, dbo.regime_ticker_metrics, dbo.pogl_trade_ledger
--   Era 21 excluded; MSFT era 4 excluded; NVDA era 7 excluded (IPO partial eras)
--
-- ATTRIBUTION RULE: a closed POGL trade's realized return is credited
-- entirely to the era in which it EXITS -- standard realization
-- accounting (gains aren't recognized until a position is closed), the
-- same convention taxes, brokers, and traders use. No mark-to-market, no
-- partial attribution to eras a trade merely passed through.
-- ============================================================================

use SecurityTradingAnalytics;
go

-- ---------------------------------------------------------------------------
-- Step 1: attribute each closed POGL trade to its exit era, aggregate to
-- one row per (era_id, ticker) -- summed, not compounded, realized return.
-- ---------------------------------------------------------------------------
if object_id('tempdb..#pogl_era_agg') is not null drop table #pogl_era_agg;

select
    m.era_id,
    t.ticker,
    count(*)                          as pogl_closed_trade_count,
    sum(t.realized_return_pct)        as pogl_era_pct_return
into #pogl_era_agg
from dbo.pogl_trade_ledger t
inner join dbo.market_regime_ledger m
    on t.exit_date >= m.start_date
    and t.exit_date <= m.end_date
where t.exit_date is not null          -- closed trades only
group by m.era_id, t.ticker;
go

-- ---------------------------------------------------------------------------
-- Step 2: join to the buy-and-hold era metrics, apply the exclusion list.
-- Zero-trade eras get pogl_era_pct_return = 0 via isnull() -- POGL held
-- cash, so it's credited with a flat 0% for that era, same as it would
-- show on a brokerage statement with no closed positions.
-- ---------------------------------------------------------------------------
if object_id('tempdb..#era_comparison') is not null drop table #era_comparison;

select
    rtm.ticker,
    rtm.era_id,
    isnull(p.pogl_closed_trade_count, 0)   as pogl_closed_trade_count,
    rtm.overall_pct_return                 as bh_overall_pct_return,
    isnull(p.pogl_era_pct_return, 0)       as pogl_era_pct_return
into #era_comparison
from dbo.regime_ticker_metrics rtm
left join #pogl_era_agg p
    on p.era_id = rtm.era_id
    and p.ticker = rtm.ticker
where rtm.era_id <> 21                                   -- open era, all tickers
    and not (rtm.ticker = 'MSFT' and rtm.era_id = 4)      -- MSFT IPO partial era
    and not (rtm.ticker = 'NVDA' and rtm.era_id = 7);     -- NVDA IPO partial era
go

-- ---------------------------------------------------------------------------
-- Result set 1: per-ticker mean pct return -- ALL eligible eras, zero-trade
-- eras included. zero_trade_era_count rides along with the means because
-- it's the denominator context for interpreting the spread: a wide spread
-- concentrated in a couple of sat-out eras reads very differently from a
-- spread built up thinly across many.
-- ---------------------------------------------------------------------------
select
    ticker,
    count(*)                                                       as eligible_era_count,
    sum(case when pogl_closed_trade_count = 0 then 1 else 0 end)   as zero_trade_era_count,
    cast(avg(bh_overall_pct_return) as numeric(10,4))              as bh_overall_pct_return_mean,
    cast(avg(pogl_era_pct_return) as numeric(10,4))                as pogl_era_pct_return_mean,
    cast(avg(pogl_era_pct_return) - avg(bh_overall_pct_return) as numeric(10,4))
                                                                    as overall_return_spread
from #era_comparison
group by ticker
order by ticker;
go

-- ---------------------------------------------------------------------------
-- Result set 2: pooled "ALL TICKERS" mean pct return -- all eligible
-- era-ticker rows across all six tickers combined into one set (not an
-- average of the six per-ticker means).
-- ---------------------------------------------------------------------------
select
    'ALL TICKERS'                                                       as ticker,
    count(*)                                                            as eligible_era_count,
    sum(case when pogl_closed_trade_count = 0 then 1 else 0 end)        as zero_trade_era_count,
    cast(avg(bh_overall_pct_return) as numeric(10,4))                   as bh_overall_pct_return_mean,
    cast(avg(pogl_era_pct_return) as numeric(10,4))                     as pogl_era_pct_return_mean,
    cast(avg(pogl_era_pct_return) - avg(bh_overall_pct_return) as numeric(10,4))
                                                                         as overall_return_spread
from #era_comparison;
go

Appendix B: Code for the second image in the Contrasting POGL Trade Performance Versus Buy-and-Hold Investing Section

-- bh_overall_pct_return results for

-- 20 JPM-era pairs

select

    ticker,

    era_id,

    era_name,

    regime,

    overall_pct_return as bh_overall_pct_return

from dbo.regime_ticker_metrics

where ticker = 'JPM'

    and era_id <> 21          -- keep consistent with the series' open-era exclusion

order by era_id;


Appendix C: Code for the third image in the Contrasting POGL Trade Performance Versus Buy-and-Hold Investing Section

-- ============================================================================

-- POGL vs. Buy-and-Hold -- Capital-at-Risk Adjusted Return by Era

-- ============================================================================

-- Part 2 of a two-script pair supporting the "Contrasting POGL Trade

-- Performance Versus Buy-and-Hold Investing" post section. Companion to

-- pogl_vs_bh_mean_pct_return.sql, which answers "which approach

-- accumulated more return over the full era." This script asks a

-- different question: when POGL's capital was actually deployed, how did

-- its rate of return compare to buy-and-hold's continuous exposure?

--

-- WHY EACH SIDE GETS ITS OWN DENOMINATOR:

-- Buy-and-hold is invested for an era's entire span, so that era's own

-- trading_days figure IS buy-and-hold's true days-at-risk -- dividing its

-- era return by trading_days gives a real per-day rate for buy-and-hold.

--

-- POGL is not the same shape. A closed trade's return is credited

-- entirely to its EXIT era (realization accounting -- see the attribution

-- rule below), but the trade may have been open far longer than that

-- era's own span. Confirmed example from this series: a trade with 1,103

-- days of exposure (holding_period_bars) closing inside a 23-trading-day

-- era. Dividing that trade's return by the exit era's 23 trading days

-- would overstate its daily rate roughly 48x relative to dividing by the

-- 1,103 days the capital was actually at risk. So POGL's rate here

-- divides by pogl_exposure_days -- the summed holding_period_bars of

-- whichever trades closed in that era -- not by the era's own

-- trading_days.

--

-- This keeps both sides on realization accounting throughout (no

-- mark-to-market, no reinvestment/compounding assumption across trades)

-- while giving each side a denominator that reflects its own actual days

-- at risk, not a denominator borrowed from the other strategy.

--

-- POPULATION: unlike the mean-pct-return script, this comparison can only

-- be computed for eras where POGL held at least one position --

-- pogl_exposure_days is 0 in a zero-trade era, and a return-per-day-at-

-- risk figure is undefined when no capital was at risk. So this script

-- uses active_era_count (matching the convention from the earlier

-- active-eras-only rollup), not eligible_era_count -- the sample sizes

-- here and in the mean-pct-return table will differ, and that's expected,

-- not an error.

--

-- Same table sources and exclusions as prior scripts in this series:

--   dbo.market_regime_ledger, dbo.regime_ticker_metrics, dbo.pogl_trade_ledger

--   Era 21 excluded; MSFT era 4 excluded; NVDA era 7 excluded (IPO partial eras)

-- ============================================================================

 

use SecurityTradingAnalytics;

go

 

-- ---------------------------------------------------------------------------

-- Step 1: attribute each closed POGL trade to its exit era, aggregate to

-- one row per (era_id, ticker) -- summed realized return AND summed

-- exposure days (holding_period_bars) for whatever trades closed there.

-- Because this sums both a trade's gain and its own days-held BEFORE

-- dividing, pogl_return_per_exposure_day below (Step 2) works out to a

-- pooled ratio -- total gain / total days -- rather than an average of

-- separate per-trade rates, so a quick trade and a long-held trade

-- closing in the same era aren't treated as equally-weighted data points.

-- ---------------------------------------------------------------------------

if object_id('tempdb..#pogl_era_agg') is not null drop table #pogl_era_agg;

 

select

    m.era_id,

    t.ticker,

    count(*)                          as pogl_closed_trade_count,

    sum(t.realized_return_pct)        as pogl_era_pct_return,

    sum(t.holding_period_bars)        as pogl_exposure_days

into #pogl_era_agg

from dbo.pogl_trade_ledger t

inner join dbo.market_regime_ledger m

    on t.exit_date >= m.start_date

    and t.exit_date <= m.end_date

where t.exit_date is not null          -- closed trades only

group by m.era_id, t.ticker;

go

 

-- ---------------------------------------------------------------------------

-- Step 2: join to buy-and-hold era metrics, apply the exclusion list,

-- compute each side's own per-day rate -- bh divided by the era's

-- trading_days (bh's real exposure), pogl divided by pogl_exposure_days

-- (pogl's real exposure).

-- ---------------------------------------------------------------------------

if object_id('tempdb..#era_comparison') is not null drop table #era_comparison;

 

select

    rtm.ticker,

    rtm.era_id,

    rtm.trading_days,

    isnull(p.pogl_closed_trade_count, 0)   as pogl_closed_trade_count,

    isnull(p.pogl_exposure_days, 0)        as pogl_exposure_days,

    cast(rtm.overall_pct_return / nullif(rtm.trading_days, 0) as numeric(10,4))

                                            as bh_return_per_trading_day,

    cast(isnull(p.pogl_era_pct_return, 0) / nullif(p.pogl_exposure_days, 0) as numeric(10,4))

                                            as pogl_return_per_exposure_day

into #era_comparison

from dbo.regime_ticker_metrics rtm

left join #pogl_era_agg p

    on p.era_id = rtm.era_id

    and p.ticker = rtm.ticker

where rtm.era_id <> 21                                   -- open era, all tickers

    and not (rtm.ticker = 'MSFT' and rtm.era_id = 4)      -- MSFT IPO partial era

    and not (rtm.ticker = 'NVDA' and rtm.era_id = 7);     -- NVDA IPO partial era

go

 

-- ---------------------------------------------------------------------------

-- Result set 1: per-ticker capital-at-risk adjusted mean return, active

-- eras only (pogl_closed_trade_count > 0 -- required for

-- pogl_return_per_exposure_day to be defined; see population note above).

-- ---------------------------------------------------------------------------

select

    ticker,

    count(*)                                                            as active_era_count,

    cast(avg(bh_return_per_trading_day) as numeric(10,4))               as bh_return_per_trading_day_mean,

    cast(avg(pogl_return_per_exposure_day) as numeric(10,4))            as pogl_return_per_exposure_day_mean,

    cast(avg(pogl_return_per_exposure_day) - avg(bh_return_per_trading_day) as numeric(10,4))

                                                                         as capital_at_risk_spread

from #era_comparison

where pogl_closed_trade_count > 0

group by ticker

order by ticker;

go

 

-- ---------------------------------------------------------------------------

-- Result set 2: pooled "ALL TICKERS" capital-at-risk adjusted mean return

-- -- all active era-ticker rows across all six tickers combined into one

-- set (not an average of the six per-ticker means).

-- ---------------------------------------------------------------------------

select

    'ALL TICKERS'                                                       as ticker,

    count(*)                                                            as active_era_count,

    cast(avg(bh_return_per_trading_day) as numeric(10,4))               as bh_return_per_trading_day_mean,

    cast(avg(pogl_return_per_exposure_day) as numeric(10,4))            as pogl_return_per_exposure_day_mean,

    cast(avg(pogl_return_per_exposure_day) - avg(bh_return_per_trading_day) as numeric(10,4))

                                                                         as capital_at_risk_spread

from #era_comparison

where pogl_closed_trade_count > 0;

go


Comments

Popular posts from this blog