SMA stands for simple moving average.
Read from the start: chapter 1 The RuleLeveraged ETFs can lose a large part of their value in a short time.
The public repository on GitHub holds example packages with invented data, a short Python script and the reference output. Running the script reproduces the reference output line by line.
What the repository holds
examples/sma-signal/input.csv: index, product price and money-market rate per trading day, plus window, buffer and trading costs.examples/sma-signal/recompute.py: the rule as a script, using only the standard library.examples/sma-signal/output.csv: the reference output, one row per trading day.examples/sma-signal/README.md: columns, calculation and set days.examples/leverage-model/input.csv: daily index return, interest rate, leverage and costs per day.examples/leverage-model/recompute.py: the leverage model as a script.examples/leverage-model/output.csv: the reference output of the leverage model.examples/leverage-model/README.md: columns and calculation of the leverage model.
Machine-readable overview: llms.txt.
Run it locally
Python 3 is all it takes; the script uses only the standard library and needs no installation.
git clone https://github.com/Andre0512/letf-strategies.git
cd letf-strategies/examples/sma-signal
python3 recompute.py input.csv > result.csv
diff result.csv output.csv
If diff prints nothing, every line matches. The same lines work in
examples/leverage-model.
The calculation in short
The first block shows the steps of the rule, one trading day after another. The second block shows the leverage model, which rebuilds the price of a product before its launch.
# Prices are adjusted for splits and distributions.
for each trading day t:
average = mean of the last WINDOW index levels up to t
in on the previous day: line = average * (1 - BUFFER / 100)
out on the previous day: line = average * (1 + BUFFER / 100)
in if the index at the close of t >= line, otherwise out
the state changes: trade at the close of the signal day,
with LAG that many trading days later
on every trade: value = value * (1 - COST / 100)
in the product: value follows the product price
out: value grows by the daily interest from max(rate, 0),
without a known rate FALLBACK = 2.5 percent per year applies
# Leverage model: price before the launch, day by day
days = calendar days since the previous day
gross = 1 + LEVERAGE * daily return of the index
ter = 1 - TER * days / 365
financing = 1 - (LEVERAGE - 1) * (rate + markup) * days / 360
only with LEVERAGE above 1, otherwise financing = 1
price = previous price * gross * ter * financing * further factors
The parameters
The page computes with these values unless someone changes them:
WINDOW = 200 # trading days; the page shows 200, 220 and 255
BUFFER = 0 # percent around the average
CONFIRMATION = 1 # days, fixed
LAG = 0 # trading days between signal and trade
COST = 0 # percent per trade
RATE = ESTR / SOFR / SONIA # overnight rate by product currency: EUR, USD, GBP
FALLBACK = 2.5 # percent per year when the rate is unknown
Your own version can change these values: the window between 50 and 500 trading days, the buffer between 0 and 5 percent and the cost per trade between 0 and 1 percent. Confirmation stays at 1 day.
Data rules
- Trading calendar: The calendar knows the exchange holidays in the US, the euro area and the UK; the world index has no holiday calendar. The next product price within 4 calendar days counts for the signal day. The display follows the calendar of the product.
- Splits and adjustment: Index and product prices are adjusted for splits and distributions.
- Reconstruction before launch: Before the first real price of a product, the page computes its price backwards with the leverage model, see the second block under "The calculation in short". From the first real price onward, the real price applies.
- Currency: If the currency of the product differs from that of the index, an exchange rate converts it for derived versions.
The columns
The input carries per trading day the date, index, product price and money-market rate, and in the first row also window, buffer and trading costs. The output has these columns:
| Column | Meaning |
|---|---|
date |
day of the row |
index_rounded |
index to two decimals, for display only |
sma |
average over the window, unrounded |
line |
average with buffer by the state of the previous day, unrounded |
line_state |
aufwaermen, drin or draussen at the closing price |
invested |
money in the product at the closing price, yes or no |
signal |
start, einstieg, ausstieg or empty |
money_interest_day |
daily money-market rate credited on that day |
trading_cost |
cost of the trade on the execution day |
value_strategy |
value of the strategy, 100 on the first day with a product price |
value_hold |
100 times product price divided by the first product price |
All columns with unit and time basis are in the README of the package.
Why two packages
sma-signal shows the rule: average, line with buffer and the decision whether
the money sits in the product or in the money market, applied to a product
price. leverage-model shows the product itself: the daily reset of the
leverage, running costs and financing, and from these the price before the
launch. Before the launch the site uses this model price, afterwards real
prices of the product.
Why invented data
Index levels and product prices belong to their providers, and their license does not allow a public repository. That is why all numbers are invented: a formula for the index and three set days for start, exit and a tie. They say nothing about a market. Anyone with their own prices puts them into the same columns.
What the page computes the same way
With the same product prices, the same signal days, the same money-market rates (without a known rate 2.5 %) and the same trading costs, the site computes the same value curve; the site compares the signal at the unrounded raw level of the index, which it does not show; the package demonstrates the same rule on its invented series. Before the launch, the leverage model stands behind it.
Eight days from the package, with a window of 210 trading days, a 1.5 % buffer and 0.15 % trading costs. On the third day the index falls below the line, the money moves to the money market, and the line jumps one buffer above the average. From the fifth day the index is above the average again, but below this line; the money stays out and earns interest.
All numbers are invented. Values since the start at 100.
| Date | Index | Line | In the market (yes/no) | Strategy value |
|---|---|---|---|---|
| 1925-11-04 | 113.43 | 111.91 | yes | 73.88 |
| 1925-11-05 | 113.56 | 111.91 | yes | 74.05 |
| 1925-11-06 | 111.34 | 111.90 | no | 74.11 |
| 1925-11-09 | 113.80 | 115.30 | no | 74.12 |
| 1925-11-10 | 113.89 | 115.30 | no | 74.13 |
| 1925-11-11 | 113.94 | 115.30 | no | 74.14 |
| 1925-11-12 | 113.95 | 115.30 | no | 74.15 |
| 1925-11-13 | 113.91 | 115.30 | no | 74.16 |