Skip to main content

afterquote

Synthetic after-hours pricing for leveraged and cross-currency securities.

PyPI version PyPI downloads CI


The London market closes at 4:30pm. TSLA keeps trading until 9pm EST. If you hold 3TSL.L — a 3× leveraged ETP in GBp — you have no live price for the next several hours. afterquote fills that gap: it synthesises a real-time OHLC quote by applying the underlying's move (with leverage and FX adjustment) to the last known close.

pip install afterquote
from afterquote import SecurityPair

pair = SecurityPair("3TSL.L", "TSLA")
pair.info()
                                base_security underlying_security  base_is_live  leverage           base_close_time  base_close_price  adj_percent_return  quote_price
quote_time
2026-06-19 00:59:00+01:00        3TSL.L               TSLA         False         3 2026-06-18 16:30:00+01:00        177.869995            0.621451   178.975369

How it works

When the base exchange is closed and the underlying is still trading, afterquote builds a synthetic quote by decomposing each underlying bar into two multiplicative legs:

  • Gap return — inter-bar move (underlying open vs its previous close), scaled by leverage
  • Intra return — intra-bar move (underlying close vs its open), scaled by leverage

For cross-currency pairs (e.g. a GBp ETP tracking a USD stock), the FX rate is fetched and applied as a separate 1× leg — so leverage applies only to the underlying's return, not the currency move.

Every synthetic candle grows from a single anchor (the base's last close), so the chain is continuous and High ≥ max(Open, Close) ≥ Low holds by construction.


Usage

Synthetic quote

pair = SecurityPair("3TSL.L", "TSLA")

pair.info()
                                base_security underlying_security  base_is_live  leverage           base_close_time  base_close_price  adj_percent_return  quote_price
quote_time
2026-06-19 00:59:00+01:00        3TSL.L               TSLA         False         3 2026-06-18 16:30:00+01:00        177.869995            0.621451   178.975369
pair.pricing()
                              Impl_Open    Impl_High     Impl_Low   Impl_Close
Datetime
2026-06-18 16:30:00+01:00  177.869995  178.077587  177.733974  178.070422
2026-06-18 16:31:00+01:00  178.070422  178.185074  177.941470  177.941470
2026-06-18 16:32:00+01:00  177.927178  177.962971  177.769626  177.884217
2026-06-18 16:33:00+01:00  177.884217  177.934294  177.619327  177.741023
2026-06-18 16:34:00+01:00  177.762466  178.141756  177.762466  177.991464
...
2026-06-19 00:59:00+01:00  178.946613  179.061640  178.946613  178.975369

[509 rows × 4 columns]

Confidence band

pair.info(confidence=0.95)
                                base_security underlying_security  base_is_live  leverage           base_close_time  base_close_price  adj_percent_return  quote_price  lower_bound  upper_bound
quote_time
2026-06-19 00:59:00+01:00        3TSL.L               TSLA         False         3 2026-06-18 16:30:00+01:00        177.869995            0.621451   178.975369      176.420      181.530

lower_bound / upper_bound come from the empirical distribution of past prediction errors — no Gaussian assumption. The band is asymmetric when errors are skewed.

Benchmark

from afterquote import benchmark, metrics

results = benchmark(pair, days=90)
print(results)
            base_close   synth_open  actual_open    residual  direction_correct
2026-03-26  148.320007  163.052340  152.440002    10.612338               True
2026-03-27  152.440002  144.918760  161.800003   -16.881240              False
2026-03-28  161.800003  174.338120  168.220001     6.118119               True
2026-03-31  168.220001  159.774480  163.559998    -3.785518               True
2026-04-01  163.559998  141.832900  129.680008    12.152892               True
...
2026-06-18  177.869995  179.341200  178.240005     1.101195               True

[62 rows × 5 columns]
metrics(results)
{'rmse': 74.1, 'mae': 58.3, 'direction_correct': 0.71, 'tracking_error': 61.2, 'n': 62}

The model called the direction right 71% of the time over 62 sessions.

Correlation health check

pair.correlation()
# 0.7612

Pearson daily-return correlation between base and underlying over the last 90 days. Emits UserWarning when |corr| < 0.5.

Portfolio P&L

holdings.csv:

base,underlying,quantity
3TSL.L,TSLA,1000
3USL.L,SPY,500
from afterquote import portfolio_pnl

portfolio_pnl("holdings.csv")
     base underlying  quantity  base_close_price  quote_price      pnl
   3TSL.L       TSLA    1000.0        177.869995   178.975369  1105.37
   3USL.L        SPY     500.0        312.540001   313.706240   583.12
    TOTAL                1500.0               NaN          NaN  1688.49

Point-in-time queries

All methods accept as_of for historical reconstruction — no look-ahead bias:

pair.info(as_of=pd.Timestamp("2026-06-18 20:00:00-04:00"))
pair.pricing(as_of=pd.Timestamp("2026-06-18 20:00:00-04:00"))

CLI

afterquote 3TSL.L TSLA                                    # synthetic quote
afterquote 3TSL.L TSLA --confidence 0.95                  # with confidence band
afterquote 3TSL.L TSLA --pricing                          # full OHLC bars
afterquote 3TSL.L TSLA --benchmark                        # backtest + metrics
afterquote 3TSL.L TSLA --correlation                      # correlation check
afterquote 3TSL.L TSLA --as-of "2026-06-18 20:00-04:00"  # historical query
afterquote --holdings holdings.csv                        # portfolio P&L
$ afterquote 3TSL.L TSLA --benchmark

            base_close   synth_open  actual_open    residual  direction_correct
2026-03-26  148.320007  163.052340  152.440002    10.612338               True
...
2026-06-18  177.869995  179.341200  178.240005     1.101195               True

  rmse: 74.1
  mae: 58.3
  direction_correct: 0.71
  tracking_error: 61.2
  n: 62
$ afterquote 3TSL.L TSLA --correlation

correlation: 0.7612

Demo pairs

Pair Leverage FX Use case
3TSL.L / TSLA 3× GBp → USD Both leverage and FX active — the full model
3USL.L / SPY 3× — Leverage only — same-currency baseline

Testing

pip install -e ".[test]"
pytest tests/          # 68 unit tests, mocked, ~0.4s — no network calls
pytest tests/ --runlive  # + live yfinance validation

Contributing

Issues and PRs welcome. — Junaid

License

MIT. See LICENSE.

Metadata

Release files for afterquote 1.0.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for afterquote 1.0.0
File Size Uploaded
afterquote-1.0.0.tar.gz 23.0 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for afterquote 1.0.0
File Interpreter ABI Platform
afterquote-1.0.0-py3-none-any.whl Python 3 none any Details

Total release size: 37.8 kB

Release files / afterquote-1.0.0.tar.gz

Download URL afterquote-1.0.0.tar.gz
Size 23.0 kB
Tags Source
SHA-256 checksum
How to use checksums
067053586a1fe6dd143419ea11e9d64cd3e9d94f21e93dac69b47d256d019c7d
BLAKE2b-256 checksum
How to use checksums
c6a735c3faeda54f9e5c2edf28a39dfa36ab46baca6d290d9586e868891ac5a5
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.1.0 CPython/3.13.12

Release files / afterquote-1.0.0-py3-none-any.whl

Download URL afterquote-1.0.0-py3-none-any.whl
Size 14.8 kB
Tags Python 3
SHA-256 checksum
How to use checksums
dba07942cf9b1dbd9e382b68614d96aa250077e3f0eab0fbe75847a097ac376a
BLAKE2b-256 checksum
How to use checksums
815680e293bde3b2e49d4e3f59bfa9c17837d75b23f0b32dd67ddead45790bcd
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.1.0 CPython/3.13.12

Release history Release notifications | RSS feed

This release

1.0.0 This release

2 release files

0.3.0

2 release files

0.2.1

2 release files

0.2.0

2 release files

0.1.3

2 release files

0.1.2

2 release files

0.1.1

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page