Category Archives: Trend Following

Monte Carlo: Garbage or Gold?

A quick history of Monte Carlo (the short version)

 

Monte Carlo Tool Link:  Read blog first:  Monte Carlo Trade Flight Simulator · Streamlit

Youtube Video on Monte Carlo Tool:  Youtube Monte Carlo Tool Video

Monte Carlo methods took off in the 1940s during wartime research at Los Alamos, when scientists needed a practical way to estimate outcomes for complex systems that couldn’t be solved with a single clean equation. Trading has the same problem: there’s no tidy formula that can tell you the order your wins and losses will arrive in—and that order is where luck lives.

So we do the next best thing: we add randomness on purpose. Monte Carlo repeatedly reshuffles the same trade outcomes to create many plausible equity paths, revealing how smooth (or brutal) the ride can be even when the system’s edge stays the same.

“No matter how sophisticated our choices, how good we are at dominating the odds, randomness will have the last word.” — Nassim Nicholas Taleb, Fooled by Randomness

What Monte Carlo does in trading

In trading system analysis, the “Monte Carlo move” is straightforward: you take your historical list of trade results (P/L per trade), then you randomly reshuffle (or resample) that list thousands of times. Each reshuffle produces a new, plausible equity curve built from the same underlying trade outcomes. From there, you measure the things that actually determine whether a system is tradeable—how deep the drawdowns get, how long the slumps can last, and how often the path gets ugly enough to force you to quit or cut size.

This doesn’t predict the future. It answers a different (and more practical) question:

Given the trade outcomes you’ve already seen, how good—or how bad—can the ride get due to sequencing alone?

That’s the value, or is it?

Why traders debate the value of Monte Carlo

Why some traders love it

  • It exposes fragility that a single backtest can hide.
    A backtest is one historical path—one specific order of wins and losses. Monte Carlo reshuffles that order to show other plausible paths. If a strategy only “works” when winners show up early, Monte Carlo will expose that quickly.

  • It turns vague fear into a measurable risk.
    Traders feel risk but struggle to quantify it. Monte Carlo lets you define a failure line (for example, “equity falls below 60% of starting capital”) and estimate how often that happens across thousands of simulated lives. You may still trade it—but now you’re choosing with a probability, not a gut feeling.

  • It helps you size the system rationally.
    Most blow-ups aren’t caused by a bad system—they’re caused by a decent system traded too big. By running the same trades under different starting capital (or leverage), Monte Carlo shows where the strategy becomes survivable. It often reveals a capital/size “threshold” where ruin risk drops and drawdowns become tolerable.

Why some traders hate it

  • It assumes the future behaves like the past.
    Monte Carlo can’t detect regime change. If your edge only works in certain “market moods” (trending vs choppy, low-vol vs high-vol), the simulation may look great right up until the market stops playing that game.

  • It assumes trades can be shuffled like a deck of cards.
    Many Monte Carlo runs treat each trade as an independent draw from the same bag of outcomes. Real systems aren’t that clean—markets come in streaks and clusters (volatility spikes, choppy stretches, correlation breaks), and those dependencies don’t always survive a simple reshuffle. Monte Carlo still helps measure sequence risk, but it isn’t a full market simulator.

  • It can punish good systems—and flatter lucky ones.
    A solid system can look worse if its history includes a few rare “tail” events—Monte Carlo will replay those tails in many sequences. Meanwhile, a strategy that enjoyed an unusually favorable historical run can look sturdier than it deserves, because the simulation is only as honest as the sample you feed it.

So, it’s not garbage… but it’s not gold automatically either.

Monte Carlo is a tool. Like any tool, it can be used well or used blindly.

The setup: how I ran these simulations

Monte Carlo Trade Flight Simulator · Streamlit

For these tests, I used my Streamlit-based Monte Carlo “Trade Flight Simulator.” You paste a column of trade P/L and the simulator generates:

  • Risk of Ruin based on a user-defined ruin line
  • Median drawdown across thousands of randomized equity paths
  • Worst-case outcomes (1st percentile)
  • Distribution visuals (“broom chart” equity fan + destination histogram)
  • Scaling table across start equity levels

Key settings used here

  • Ruin threshold: 60% of starting equity
  • Position size: 1 contract per trade
  • Execution costs: $40 per trade included in the trade list results you pasted
  • Horizon: number of trades pasted (the simulator runs “N trades” each life)
  • Optional CAGR is computed from first/last trade dates when provided

System #1: Mean Reversion on the Mini Nasdaq (MNQ)

~$40 execution costs, ~20 years

Start Equity Risk of Ruin Median DD Annual Return Worst Case (1st %)
$25,000 30% 42.9% 12.9% $85,019
$31,250 14% 36.2% 11.7% $80,747
$37,500 8% 32.2% 10.8% $93,072
$43,750 4% 30.1% 10.0% $78,308
$50,000 1% 26.4% 9.6% $81,352
$56,250 1% 25.2% 8.8% $93,765
$62,500 0% 24.4% 8.4% $77,907
$68,750 0% 23.0% 8.1% $81,076
$75,000 0% 20.6% 7.7% $81,108
$81,250 0% 19.1% 7.4% $89,028
$87,500 0% 18.9% 7.0% $81,982

System #1 — Mean Reversion (MNQ)

  • At $25,000 start equity
    • Risk of Ruin: 30%
    • Median Drawdown: 42.9%
    • Annual Return: 12.9%
    • Worst Case (1%): +$85,019
    • Prob > 0: 99.9%
  • At $50,000 start equity (“still not comfortable”)
    • Risk of Ruin: 1%
    • Median Drawdown: 26.4%
    • Annual Return: 9.6%
  • At $62,500 start equity (“stability zone”)
    • Risk of Ruin: 0%
    • Median Drawdown: 24.4%
    • Annual Return: 8.4%

What Monte Carlo reveals about this system

This is what a tradeable but under-capitalized system looks like.

The edge is real (the probability of finishing positive is essentially ~100%), but the sequence risk at low starting equity is still brutal:

  • A 30% risk of ruin at $25k (with a 60% ruin line) is not a rounding error.

  • Even at $31,250, ruin risk is still 14%.

  • The system doesn’t start to feel “professional” until you get into the $60k+ range, where ruin drops to 0% and median drawdowns settle into the mid-20% area.

Monte Carlo’s message:
If you want this system to behave like something you can actually stick with, you don’t optimize parameters — you capitalize it properly.

System #2: Trend Following on Crude Oil

~$40 execution costs, ~20 years

System #2 — Trend Following (Crude)

Start Equity Risk of Ruin Median DD Annual Return Worst Case (1%)
$25,000 68% 89.7% 8.7% -$99,928
$31,250 58% 80.7% 7.8% -$95,663
$37,500 47% 71.3% 7.1% -$100,991
$43,750 40% 64.1% 6.5% -$111,564
$50,000 31% 58.3% 6.2% -$98,846
$56,250 28% 57.0% 5.5% -$94,594
$62,500 22% 51.1% 5.3% -$100,349
$68,750 19% 49.9% 4.8% -$103,016
$75,000 16% 47.2% 4.5% -$112,968
$81,250 12% 42.3% 4.5% -$98,345
$87,500 11% 42.1% 4.0% -$98,228
  • At $25,000 start equity
    • Risk of Ruin: 68%
    • Median Drawdown: 89.7%
    • Annual Return: 8.7%
    • Worst Case (1%): -$99,928
    • Prob > 0: 87.3%
  • At $50,000 start equity
    • Risk of Ruin: 31%
    • Median Drawdown: 58.3%
    • Annual Return: 6.2%
    • Worst Case (1%): -$98,846
    • Prob > 0: 90.1%
  • At $81,250 start equity
    • Risk of Ruin: 12%
    • Median Drawdown: 42.3%
    • Annual Return: 4.5%
    • Worst Case (1%): -$98,345
    • Prob > 0: 86.4%
  • At $87,500 start equity
    • Risk of Ruin: 11%
    • Median Drawdown: 42.1%
    • Annual Return: 4.0%
    • Worst Case (1%): -$98,228
    • Prob > 0: 87.1%

What Monte Carlo reveals about this system

This is a classic crude trend-following signature: the system can be profitable over time, but the path can be violently unforgiving—especially when under-capitalized.

  • The probability of finishing positive is only in the mid-to-high 80% range, not “near-certain.”
  • At $25,000, the system is living on the edge: 68% risk of ruin with an 89.7% median drawdown.
  • Even after you scale up, the ride is still rough. At $81,250, ruin risk is still 12% with a 42.3% median drawdown.

The most important tell is the left tail: the 1% worst-case outcome is negative at every starting equity you tested (roughly –$94,594 to –$112,968). That means there are plausible sequences where the system not only suffers deep drawdowns, but ends the run down money—even with larger starting capital.

Monte Carlo’s message: This isn’t just a “start with more money” situation. Increasing capital helps, but the strategy’s tail risk remains severe. If you trade this, you need materially more capitalization, smaller sizing, or a risk overlay—because crude can deliver adverse sequences that this system does not comfortably absorb.

Which system is “superior” under your ruin rule?

You asked earlier: with a 60% ruin line and 1 contract per trade, does Monte Carlo reveal superiority?

Yes — because it reframes superiority as:

Which system survives at realistic starting equity levels with tolerable drawdowns?

Under-capitalized start: both are dangerous

At $25k, both systems are dangerous under the 60% ruin definition:

  • MNQ MR: 29% ruin, 41% median DD
  • Crude TF: 48% ruin, 55% median DD

So if someone insists on $25k and 1 contract, System #1 is clearly less fragile than System #2.

Once you move into realistic capital, System #1 stabilizes sooner

MNQ MR drops into “sane” ruin probabilities faster:

  • MNQ MR hits ~0% ruin by $56,250
  • Crude TF doesn’t really calm down until $75k–$81k

That’s not a judgment against trend following — it’s a reminder that instrument volatility matters and crude can be a different animal.

If you define “superior” as best risk-adjusted scaling

Based on your tables:

  • MNQ mean reversion looks easier to scale under your assumptions
  • Crude trend following can still be very viable, but it demands more capitalization to get into the same comfort zone

Monte Carlo didn’t make either system “good” or “bad.”
It made the capital requirements and sequence risk visible.

The visuals I include from the Streamlit app

System #1 Mean Reversion on the NQ

The Journey (“broom chart”)
Shows the median equity path with a confidence band.
Great for communicating “how rough can the ride get?”

Broom Chart

The Destination (ending equity histogram)
Think of each green bar as a bucket of endings. After 1,000 randomized runs, some endings cluster in the middle (the “typical” outcomes), while a smaller number land in the tails (the “lucky” and “unlucky” sequences). The dashed line marks your starting equity ($25,000). If the histogram sits mostly to the right, the system usually finishes positive. If a meaningful chunk sits to the left, that’s your “this can end down” reality—even with the same system and the same trades, just a different order.

Destination Histogram

Efficiency cloud (drawdown vs net profit scatter)

  • Each dot = one simulated run (“one life”).
  • Left to right (x-axis) = max drawdown during that run (more right = more pain).
  • Down to up (y-axis) = net profit at the end (higher = more gain).
  • The dotted lines mark the median drawdown and median profit, splitting the plot into four zones.
  • Best zone: upper-left (good profit with smaller drawdowns).
  • Worst zone: lower-right (big drawdowns with poor outcomes).

If most dots sit upper-left, the system is efficient. If the cloud spreads far right, the system’s edge may be real, but the ride can be brutal unless you reduce size or add capital.

Efficiency Cloud

Pros and cons of Monte Carlo (in plain English)

Pros

  • It highlights sequence risk that backtests hide
  • It gives you a practical scaling map
  • It converts drawdown fear into probability
  • It forces you to confront whether your system is truly robust or just lucky

Cons

  • Garbage in, garbage out (your trade list must be clean)
  • It assumes your future trade distribution resembles the past
  • It doesn’t simulate regime shifts (it’s not a market model)
  • It can create false confidence if you treat it as prophecy

Monte Carlo is not a crystal ball. It’s a stress test.

Conclusion: Garbage or Gold?

Monte Carlo is gold when it’s used as a risk lens.

It’s garbage only when people use it as a substitute for thinking — or when they treat it as a promise about the future.

For me, the biggest takeaway from these two systems is simple:

  • A profitable system can be untradeable if it’s under-capitalized.
  • Monte Carlo makes that obvious — quickly and brutally.
  • And it gives you something most trading metrics do not:
    a realistic map from “this looks good” to “this can survive.”

If you want to know what your system really feels like under stress, run it through my free Monte Carlo Trade Flight Simulator (Streamlit). Paste your trade list, set a starting equity, and it will generate a distribution of possible equity paths—so you can see the range of outcomes, not just the single backtest line. In a minute or two you’ll know whether your strategy is sturdy (most paths survive and grow) or fragile (too many paths crater early), and you’ll get practical numbers like “typical drawdown,” “worst-case runs,” and “probability of finishing above zero.”

Trades vs. Time: Two Monte Carlo Styles

Monte Carlo has to “shuffle” something: you can shuffle trades or you can shuffle time periods (daily/weekly/monthly returns). Trade-shuffling is great for a single system because it keeps each trade intact—entry and exit stay married—so you’re mainly testing how sensitive results are to the order trades arrive.

Devil’s Advocate: shuffling time can feel less “real,” because it breaks those trade narratives. A multi-day trade becomes a series of daily fragments, and once you reshuffle daily P/L you can build equity paths that no single set of trades could have produced exactly.

That’s the tradeoff TS-PortfolioMerge makes on purpose. It builds a daily mark-to-market equity curve (open positions are revalued each day), then resamples those daily equity changes so every system stays aligned to the same calendar. This isn’t about “reinvesting” or scaling up contracts—it’s about equity path risk: the way good and bad stretches of days create drawdowns, recovery difficulty, and survival pressure for a portfolio even when trade size stays constant.

 

A Turtle Thermometer for Trend-Following: 2025 Results

A Bare-Bones Turtle Algorithm for Gauging Trend-Following Conditions

The core Turtle rules were fully mechanical, but several operational choices, such as position sizing nuances, market selection, roll/contract handling, and execution practices were left to judgment or circumstance. Many would argue the philosophy behind the Turtles mattered as much as the rules themselves, and differing interpretations of that philosophy go a long way toward explaining why their results diverged so widely. The mechanics, however, are straightforward: you can distill them from the published books and courses, strip them down even further, and apply the resulting rule set across a broad portfolio to take the pulse of trend-following today.

I’ve worked with the Turtle framework for many years, coded numerous variants, and even compared notes with a handful of original Turtles. If any method can “take the temperature” of market trendiness, this one can. This system synthesizes a shorter-term trend mechanism (that limits execution based on the prior outcome) with a true longer term trend following entry and exit method (two months of data are used to determine entry).   Short-term trading is difficult and often falls victim to over trading.  The shorter-term entry is used to try and capitalize on the genesis of a big trend.  Preventing another trade after a winner is one method of reducing trading and chop.  If the short-term break out turns into a trend and entry is prevented, then the 55-day break out is there to capture it.  Below are the rules I extracted to build a fully mechanical, bare-bones algorithm for that purpose.

Rules Used in This Analysis

Conventions & Definitions

  • Breakout (stop basis): Enter on a stop when price exceeds the specified lookback extreme by 1 tick (or exactly at the extreme if your platform supports that).
  • N: 20-day weighted Average True Range (WATR) used for both systems.
  • Risk stop (volatility stop): A stop placed 2×N from the entry price.
  • Swing stop: For System #1, use the 10-day highest high/lowest low; for System #2, use the 20-day highest high/lowest low.
  • Closest stop wins: The active protective stop at any time is the tighter of the risk stop and the swing stop.
  • Loser vs. non-loser (for System #1’s gating rule):
    • A trade that is stopped out by 2×N is a loser.
    • A trade that exits via the 10-day swing stop (even if it’s a loss) is not counted as a loser for gating.
    • Profitable exits via the 10-day swing stop are obviously not losers.

System #1 — 20-Day Breakout (Conditional)

Purpose: Only take the next 20-day breakout if the most recent 20-day breakout resulted in a 2×N loss.

  • Entry condition (gated):
    • Compute the 20-day Donchian channel.
    • You may only take a long (new 20-day high) or short (new 20-day low) breakout if the last System #1 trade ended with a 2×N risk stop.
    • If the last System #1 trade exited via the 10-day swing stop, it does not unlock the gate.
  • Initial protective stops (at entry):
    • Risk stop: 2×N from entry.
    • Swing stop: Opposite extreme of the past 10 days (lowest low for longs, highest high for shorts).
    • Use the tighter of the two stops at all times (“closest stop wins”).
  • Exit rules:
    • Exit if price hits the active stop (risk or swing).
  • Bookkeeping for gating:
    • If exit was the 2×N risk stop, mark the trade as a loser (this unlocks the gate for the next entry).
    • If exit was the 10-day swing stop, do not mark as a loser (gate remains locked).
  • Always evaluating: System #1’s breakout logic runs continuously, but entries are allowed only when the gate is unlocked by a prior 2×N loss.


System #2 — 55-Day Breakout (Always On)

Purpose: Classic trend capture that runs regardless of System #1’s state; does not affect System #1’s gating.

  • Entry condition (ungated):
    • Enter long on a 55-day high breakout; enter short on a 55-day low breakout.
  • Initial protective stops (at entry):
    • Risk stop: 2×N from entry.
    • Swing stop: Opposite extreme of the past 20 days (lowest low for longs, highest high for shorts).
    • Use the tighter of the two stops at all times.
  • Exit rules:
    • Exit if price hits the active stop (risk or swing).
  • Isolation from System #1:
    • System #2 trades and outcomes do not influence System #1’s “last-trade-was-a-loser” gate (also known as a filter).

The Portfolio

Currencies (CME FX)

Preferred name Short Futures ticker
Australian Dollar AUD @AD (6A)
British Pound GBP @BP (6B)
Canadian Dollar CAD @CD (6C)
Euro EUR @EC (6E)
Japanese Yen JPY @JY (6J)
Swiss Franc CHF @SF (6S)

Rates (CBOT)

Preferred name Short Futures ticker
30-Year U.S. Treasury Bond 30Y @US (ZB)
10-Year U.S. Treasury Note 10Y @TY (ZN)
5-Year U.S. Treasury Note 5Y @FV (ZF)

Equity/Index

Preferred name Short Futures ticker
E-mini S&P 500 ES @ES (CME)
U.S. Dollar Index DXY @DX (ICE)

Metals (COMEX/NYMEX)

Preferred name Short Futures ticker
Gold XAU @GC
Copper Cu @HG
Silver XAG @SI
Palladium Pd @PA=11INC
Platinum Pt @PL

Energies (NYMEX)

Preferred name Short Futures ticker
RBOB Gasoline RBOB @RB
Heating Oil HO @HO
WTI Crude Oil WTI @CL
Henry Hub Natural Gas NatGas @NG

Grains/Oilseeds (CBOT)

Preferred name Short Futures ticker
Soybeans Beans @ZS
Corn Corn @ZC
Rough Rice Rice @ZR
Wheat (SRW) Wheat @ZW
Soybean Meal Meal @ZM

Livestock (CME)

Preferred name Short Futures ticker
Feeder Cattle Feeders @FC (GF )
Live Cattle LiveCat @LC (LE )
Lean Hogs Hogs @LH (HE)

Softs (ICE)

Preferred name Short Futures ticker
Frozen Concentrated Orange Juice OJ @OJ
Sugar No. 11 Sugar @SB
Cotton No. 2 Cotton @CT
Coffee “C” Coffee @KC
Lumber Lumber @LBR = @LB legacy

Market Normalization (Fixed-Fractional Sizing)

To level the playing field across markets, I used fixed-fractional position sizing keyed to the Turtle “quick” 20-day ATR.

Risk budget per trade

  • Account equity =$250,000
  • Fraction at risk per trade =2%
  • Dollar risk per trade: = × = 0.02 × 250,000 = $5,000

Contracts to trade

  • Let ATR = 20-day (Turtle quick) Average True Range in price units
  • Let BPV = Big Point Value (dollars per 1.0 move)
  • Dollar risk per 1 contract: ATR × BPV
  • Position size (contracts):
  • Contracts =⌊ / ATR × BPV⌋

In words: allocate $5,000 of risk to each trade and size the position by dividing that risk by the market’s expected dollar move (ATR×BPV).   Round down to an integer.

Notes & conventions
  • ATR is the 20-day Turtle quick ATR (same used in the rules).
  • Use the correct BPV for each contract (e.g., ES $50/pt, CL $1,000/pt, SI $5,000/pt).
  • Enforce at least on contract per signal.
  • $50 slippage and $10 commission per round turn.

Results

Large portfolio performance on Bare Bones Turtle

This equity curve is very typical across the spectrum of most trend following systems.  There have been big years to keep the trend following momentum going – recently 2008, 2010, 2014, 2018, 2020.

Big Years – pushes the popularity of Trend Following

Many times, the futures and commodity markets are there to benefit from global events such as the banking collapse (2008) and the pandemic (2020).

Over the years, markets have fallen in and out of favor with Trend Following.  The best market over the past twenty years or so turned out to be sugar.  With its smaller size and associated volatility and trends it was the clear winner.

Many HOT SPOTS on the Correlation Heat Map

Pearson Correlation Matrix

But, what about smaller accounts?

There exist sub portfolios with better profit to draw down ratios.  If you could only choose ten markets and wanted to know the best combination, you can do this with my TS-PortfolioMerge software.  In fact, all the metrics and images I have shown in this post were generated with TS-PortfolioMerge.  If your budget only allows for 10 markets and you want to evaluate every combination you will need to wait a while for TS-PM to run through every combination.

Search space C(37,10) = 348,330,136 (subset) – yes that is 300 million combinations.  Just set up your computer for overnight processing.

But if you want a speedy answer, that will approximate the entire search space you can do that as well.

Sampled (limit 50,000; randomized).

# P/DD Net Profit ($) Max DD ($) Symbols
1 12.071 1,615,758.97 133,857.91 @EC, @HG, @HO, @JY, @LB=11INC, @LH, @RB, @SB, @SM, @TY
2 11.676 1,333,359.10 114,194.85 @FC, @GC, @HO, @KC, @LB=11INC, @LBR=11INC, @LH, @OJ, @SB, @SM
3 11.563 1,473,201.00 127,410.20 @C, @CL, @EC, @ES, @GC, @HG, @HO, @LBR=11INC, @LH, @SB
4 11.545 1,601,806.50 138,745.50 @C, @CL, @CT, @GC, @HO, @LH, @RB, @SB, @SM, @US
5 11.444 1,427,082.85 124,705.40 @CL, @GC, @HO, @KC, @LB=11INC, @LBR=11INC, @LH, @OJ, @S, @SB

Run the speedy version multiple times to see if the same portfolio bubbles to the top.  If you continue getting different portfolios, you can run the exhaustive mode.  Here the best 10 markets were:

@EC, @HG, @HO, @JY, @LB=11INC, @LH, @RB, @SB, @SM, @TY

Here you have two currencies (EC and JY), one metal (HG), two energies (HO and RBOB), one interest rate (TY), sugar, lumber, soybean meal and lean hogs.  But are we guilty of cherry picking?  Maybe the Monte Carlo analysis will provide some insight.

Monte Carlo Analysis on 10 of the best combination from the Speedy output.

Conclusion

Trend Following as of late October 2025 is doing well and doing as expected.  The pandemic pulled the algorithm out of the doldrums and positive years have been banked since.  The current year looks like the exception, but we still have two months left.  With the Gold move you would think 2025 would have been a banner year.  The Trend is STILL OUR FRIEND.

Email me if you would like my code for my bare bones Turtle system, I utilized to create all these results.  The code includes the human curated LAST TRADE WAS A LOSER function.

Prune Your Trend Following Algorithm

Multiple trading decisions based on “logic” may not add to the bottom line

In this post, I will present a trend following system that uses four exit techniques.  These techniques are based on experience and also logic.  The problem with using multiple exit techniques is that it is difficult to see the synergy that is generated from all the moving parts.  Pruning your algorithm may help cut down on invisible redundancy and opportunities to over curve fit.  The trading strategy I will be presenting will use a very popular entry technique overlaid with trade risk compression.

Entry logic

Long:

Criteria #1:  Penetration of the closing price above an 85 day (closing prices) and 1.5X standard deviation-based Bollinger Band.

Criteria #2:  The mid-band or moving average must be increasing for the past three consecutive days.

Criteria #3: The trade risk (1.5X standard deviation) must be less than 3 X average true range for the past twenty days and also must be less than $4,500.

Risk is initially defined by the standard deviation of the market but is then compared to $4,500. If the trade risk is less than $4,500, then a trade is entered. I am allowing the market movement to define risk, but I am putting a ceiling on it if necessary.

Short:

Criteria #1:  Penetration of the closing price below an 85 day (closing prices) and 1.5X standard deviation-based Bollinger Band.

Criteria #2:  The mid-band or moving average must be decreasing for the past three consecutive days.

Criteria #3:  Same as criteria #3 on the long side

Exit Logic

Exit #1:  Like any Bollinger Band strategy, the mid band or moving average is the initial exit point.  This exit must be included in this particular strategy, because it allows exits at profitable levels and works synergistically with the entry technique.

Exit #2:  Fixed $ stop loss ($3,000)

Exit #3:  The mid-band must be decreasing for three consecutive days and today’s close must be below the entry price.

Exit #4:  Todays true range must be greater than 3X average true range for the past twenty days, and today’s close is below yesterday’s, and yesterday’s close must be below the prior days.

Here is the logic of exits #2 through exit #4.  With longer term trend following system, risk can increase quickly during a trade and capping the maximum loss to $3,000 can help in extreme situations.  If the mid-band starts to move down for three consecutive days and the trade is underwater, then the trade probably should be aborted.  If you have a very wide bar and the market has closed twice against the trade, there is a good chance the trade should be aborted.

Short exits use the same logic but in reverse.  The close must close below the midband, or a $3,000 maximum loss, or three bars where each moving average is greater than the one before, or a wide bar and two consecutive up closes.

Here is the logic in PowerLanguage/EasyLanguage that includes the which exit seletor.

[LegacyColorValue = true]; 
Inputs: maxEntryRisk$(4500),maxNATRLossMult(3),maxTradeLoss$(3000),
indicLen(85),numStdDevs(1.5),highVolMult(3),whichExit(7);

Vars: upperBand(0), lowerBand(0),slopeUp(False),slopeDn(False),
largeAtr(0),sma(0),
initialRisk(0),tradeRisk(0),
longLoss(0),shortLoss(0),permString("");

upperBand = bollingerBand(close,indicLen,numStdDevs);
lowerBand = bollingerBand(close,indicLen,-numStdDevs);
largeATR = highVolMult*(AvgTrueRange(20));

sma = average(close,indicLen);

slopeUp = sma>sma[1] and sma[1]>sma[2] and sma[2]>sma[3];
slopeDn = sma<sma[1] and sma[1]<sma[2] and sma[2]<sma[3];

initialRisk = AvgTrueRange(20);
largeATR = highVolMult * initialRisk;
tradeRisk = (upperBand - sma);
// 3 objects in our permutations
// exit 1, exit 2, exit 3
// perm # exit #
// 1 1
// 2 1,2
// 3 1,3
// 4 2
// 5 2,3
// 6 3
// 7 1,2,3

if whichExit = 1 then permString = "1";
if whichExit = 2 then permString = "1,2";
if whichExit = 3 then permString = "1,3";
if whichExit = 4 then permString = "2";
if whichExit = 5 then permString = "2,3";
if whichExit = 6 then permString = "3";
if whichExit = 7 then permString = "1,2,3";



{Long Entry:}
If (MarketPosition = 0) and
Close crosses above upperBand and slopeUp and
(tradeRisk < initialRisk*maxNATRLossMult and tradeRisk<maxEntryRisk$/bigPointValue) then
begin
Buy ("LE") Next Bar at Market;
End;


{Short Entry:}

If (MarketPosition = 0) and slopeDn and
Close crosses below lowerBand and
(tradeRisk < initialRisk*maxNATRLossMult and tradeRisk<maxEntryRisk$/bigPointValue) then
begin
Sell Short ("SE") Next Bar at Market;
End;


{Long Exits:}

if marketPosition = 1 Then
Begin
longLoss = initialRisk * maxNATRLossMult;
longLoss = minList(longLoss,maxTradeLoss$/bigPointValue);

If Close < sma then
Sell ("LX Stop") Next Bar at Market;;

if inStr(permString,"1") > 0 then
sell("LX MaxL") next bar at entryPrice - longLoss stop;

if inStr(permString,"2") > 0 then
If sma < sma[1] and sma[1] < sma[2] and sma[2] < sma[3] and close < entryPrice then
Sell ("LX MA") Next Bar at Market;
if inStr(permString,"3") > 0 then
If TrueRange > largeATR and close < close[1] and close[1] < close[2] then
Sell ("LX ATR") Next Bar at Market;
end;

{Short Exit:}

If (MarketPosition = -1) Then
Begin

shortLoss = initialRisk * maxNATRLossMult;
shortLoss = minList(shortLoss,maxTradeLoss$/bigPointValue);
if Close > sma then
Buy to Cover ("SX Stop") Next Bar at Market;

if inStr(permString,"1") > 0 then
buyToCover("SX MaxL") next bar at entryPrice + shortLoss stop;

if inStr(permString,"2") > 0 then
If sma > sma[1] and sma[1] > sma[2] and sma[2] > sma[3] and close > entryPrice then
Buy to Cover ("SX MA") Next Bar at Market;
if inStr(permString,"3") > 0 then
If TrueRange > largeAtr and close > close[1] and close[1] > close[2] then
Buy to Cover ("SX ATR") Next Bar at Market;
end;
Trend following with exit selector

Please note that I modified the code from my original by forcing the close to cross above or below the Bollinger Bands.  There is a slight chance that one of the exits could get you out of a trade outside of the bands, and this could potentially cause and automatic re-entry in the same direction at the same price.  Forcing a crossing, makes sure the market is currently within the bands’ boundaries.

This code has an input that will allow the user to select which combination of exits to use.

Since we have three exits, and we want to evaluate all the combinations of each exit separately, taken two of the exits and finally all the exits, we will need to rely on a combinatorial table.    In long form, here are the combinations:

3 objects in our combinations of exit 1, exit 2, exit 3

  • one  – 1
  • two  – 1,2
  • three  –  1,3
  • four –  2
  • five  – 2,3
  • six –  3
  • seven  –  1,2,3

There are a total of seven different combinations. Given the small set, we can effectively hard-code this using string manipulation to create a combinatorial table. For larger sets, you may find my post on the Pattern Smasher beneficial. A robust programming language like Easy/PowerLanguage offers extensive libraries for string manipulation. The inStr string function, for instance, identifies the starting position of a substring within a larger string. When keyed to the whichExit input, I can dynamically recreate the various combinations using string values.

  1. if whichExit = 1 then permString = “1”
  2. if whichExit = 2 then permString= “1,2”
  3. if whichExit = 3 then permString = “1,2,3”
  4.  etc…

As I optimize from one to seven, permString will dynamically change its value, representing different rows in the table. For my exit logic, I simply check if the enumerated string value corresponding to each exit is present within the string.

	if inStr(permString,"1") > 0 then
sell("LX MaxL") next bar at entryPrice - longLoss stop;
if inStr(permString,"2") > 0 then
If sma < sma[1] and sma[1] < sma[2] and sma[2] < sma[3] and close < entryPrice then
Sell ("LX MA") Next Bar at Market;
if inStr(permString,"3") > 0 then
If TrueRange > largeATR and close < close[1] and close[1] < close[2] then
Sell ("LX ATR") Next Bar at Market;
Using inStr to see if the current whichExit input applies

When permString = “1,2,3” then all exits are used.  If permString = “1,2”, then only the first two exits are utilized.  Now all we need to do is optimize whichExit from 1 to 7.  Let’s see what happens:

Combination of all three exits

The best combination of exits was “3”.  Remember 3 is the permString  that = “1,3” – this combination includes the money management loss exit, and the wide bar against position exit.  It only slightly improved overall profitability instead of using all the exits – combo #7.  In reality, just using the max loss stop wouldn’t be a bad way to go either.  Occam uses his razor to shave away unnecessary complexities again!

If you like this code, you should check out the Summer Special at my digital store. I showcase over ten more trend-following algorithms with different entry and exit logic constructs.  These other algorithms are derived from the best Trend Following “Masters” of the twentieth century.  IMHO!

Here is a video you can watch that goes over the core of this trading strategy.

 

How to Fix the Fixed Fractional Position Size

The Fixed Fractional position sizing scheme is the most popular, so why does it need fixed?

Problems solved with Fixed Fractional:

  1. Efficient usage of trading capital
  2. Trade size normalization between different futures contracts
  3. Trade size normalization across different market environments

These are very good reasons why you should use positions sizing.  Problem #2 doesn’t apply if you are only trading one market.  This sounds idyllic, right?  It solves these two problems, but it introduces a rather bothersome side effect – huge draw down.  Well, huge draw down in absolute terms.  Draw downs when using a fixed fractional approach are proportional to the prior run up.  If you make a ton of money on a prior trade, then your position sizing reflects that big blip in the equity curve.  So, if you have a large loser following a large winner, the draw down will be a function of the run up.  In most cases, a winning trading system using fixed fractional position sizing will scale profit up as well as draw down.  A professional money manager will look at the profit to draw down ratio instead of the absolute draw down value.  The efficient use of capital will reflect a smaller position size after a draw down, so that is good right?  It is unless you believe in a Martingale betting algorithm – double up on losses and halve winners.  Are we just stuck with large “absolute” draw downs when using this size scheme?

Possible solutions to fixing Fixed Fractional (FF)

The first thing you can do is risk less than the industry standard 2% per trade.  Using 1% will cause equity to grow at a slower rate and also reduce the inevitable draw down.  But this doesn’t really solve the problem as we are giving up the upside.  And that might be okay with you.  Profit will increase and you are using an algorithm for size normalization.  In this blog I am going to propose a trading equity adjustment feature while using FF.  What if we act like money managers, and you should even if you are trading your own personal money, and at the end of the year or month we take a little off the table (theoretically – we are not removing funds from the account just from the position sizing calculation) that is if there is any extra on the table.  This way we are getting the benefit of FF while removing a portion of the compounding effect, which reduces our allocation for the next time interval.  How do you program such a thing?  Well first off let’s code up the FF scheme.

positionSize = round((tradingCapital * riskPerTrade) / (avgTrueRange(30)*bigPointValue),0);

Nothing new here.  Simply multiply tradingCapital by the riskPerTrade (1 or 2%) and then divide by a formula that defines current and inherent market risk.  This is where you can become very creative.  You could risk the distance between entry and exit if you know those values ahead of time or you can use a value in terms of the current market.  Here I have chosen the 30-day average true range.  This value gives a value that predicts the market movement into the future.  However, this value only gives the expected market movement for a short period of time into the future.  You could us a multiplier since you will probably remain in a trade for more than a few days – that is if you are trying to capture the trend.  In my experiment I just use one as my multiplier.

Capture and store the prior year/month NetProfit

When I come up with a trading idea I usually just jump in and program it.  I don’t usually take time to see if Easy Language already provides a solution for my problem.   Many hours have been used to reinvent the wheel, which isn’t always a bad thing.  So, I try to take time and search the functions to see if the wheel already exists.  This time it looks like I need to create the wheel.  I will show the code first and then explain afterward.

inputs: useAllocateYearly(True),useAllocateMonthly(False),initCapital(100000),removePerProfit(0.50),riskPerTrade(0.01);
vars: tradingCapital(0),prevNetProfit(0),tradingCapitalAdjustment(0);
vars: oLRSlope(0),oLRAngle(0),oLRIntercept(0), oLRValueRaw(0),mp(0);
arrays: yearProfit[250](0),snapShotNetProfit[250](0);vars: ypIndex(0);


once
begin
tradingCapital = initCapital;
end;

if useAllocateYearly then
begin
value1 = year(d);
value2 = year(d[1]);
end;

if useAllocateMonthly then //remember make sure your array is 12XNumYears
begin
value1 = month(d);
value2 = month(d[1]);
end;

if useAllocateYearly or useAllocateMonthly then
begin
if value1 <> value2 then
begin
if ypIndex > 0 then
yearProfit[ypIndex] = prevNetProfit - snapShotNetProfit[ypIndex-1]
else
yearProfit[ypIndex] = prevNetProfit;

snapShotNetProfit[ypIndex] = prevNetProfit;
tradingCapitalAdjustment = yearProfit[ypIndex];
if yearProfit[ypIndex] > 0 then
tradingCapitalAdjustment = yearProfit[ypIndex] * (1-removePerProfit);
tradingCapital = tradingCapital + tradingCapitalAdjustment;
print(d,",",netProfit,",",yearProfit[ypIndex],",",tradingCapitalAdjustment,",",tradingCapital);
ypIndex +=1;
end;
end
else
tradingCapital = initCapital + netProfit;
Capture either the prior years or months net profit

I wanted to test the idea of profit retention on a monthly and yearly basis to see if it made a difference.  I also wanted to just use the vanilla version of FF.  The use of Arrays may not be necessary, but I didn’t know ahead of time.  When you program on the fly, which is also called “ad hoc” programming you create first and then refine later.  Many times, the “ad hoc” version turns out to be the best approach but may not be the most efficient.  Like writing a book, many times your code needs revisions.  When applying a study or strategy that uses dates to a chart, you don’t know exactly when the data starts so you always need to assume you are starting in the middle of a year.   If you are storing yearly data into an array, make sure you dimension you array sufficiently.  You will need 12X the number of years as the size you need to dimension your array if you want to store monthly data.

 


//250 element array will contain more than 20 years of monthly data
//You could increase these if you like just to be safe
arrays: yearProfit[250](0),snapShotNetProfit[250](0);
//Remember you dimension you arrray variable first and then
//Pass it a value that you want to initiate all the values
//in the array to equal
vars: ypIndex(0);
Dimension and Initiate Your Arrays

The first thing we need to do is capture the beginning of the year or month.  We can do this by using the year and month function.  If the current month or year value is not the same as the prior day’s month or year value, then we know we crossed the respective timeline boundary.  We are using two arrays, snapShotNetProfit and yearProfit (to save time I use this array to store monthlty values as well, when that option is chosen) and a single array index ypIndex.  If we have crossed the time boundary, the first thing we need to do is capture the EasyLanguage function NetProfit’s value.  NetProfit keeps track of the cumulative closed out trade profits and losses. Going forward in this description I am going to refer to a yearly reallocation.  If it’s the first year, the ypIndex will be zero, and in turn the first year’s profit will be the same as netProfit.  We store netProfit in the yearProfit array at the ypIndex location.  Since we are in a new year, we take a snapshot of netProfit and store it in the snapShotNetProfit array at the same ypIndex location.  You will notice I use the variable prevNetProfit in the code for netProfit.  Here is where the devil is in the details.  Since we are comparing today’s year value with yesterday’s year value and when they are different, we are already inside the new year, so we need to know yesterday’s netProfit.   Before you say it, you can’t pass netProfit a variable for prior values; you know like netProfit(1) or netProfit[1] – this is a function that has no historic values, but you can record the prior day’s value by using our own prevNetProfit  variable.  Now we need to calculate the tradingCapitalAdjustment.  The first thing we do is assign the variable the value held in  yearProfit[ypIndex].  We then test the yearProfit[ypIndex] value to see if it is positive.  If it is, then we multiply it by (1-removePerProfit).  If you want to take 75% of the prior year’s profit off the table, then you would multiply the prior year’s profit by 25%.  Let’s say you make $10,000 and you want to remove $7,500, then all you do is multiply $10,000 by 25%.  If the prior year’s netProfit is a loss, then this value flows directly through the code to the position sizing calculation (auto deallocation on a losing year).   If not, the adjusted profit portion of funds are deallocated in the position sizing equation.

The next time we encounter a new year, then we know this is the second year in our data stream, so we need to subtract last year’s snapshot of netProfit (or prevNetProfit) from the current netProfit.  This will give us the change in the yearly net profit.  We stuff this information into the yearProfit array.  The snapShotNetProfit is stuffed with the current prevNetProfit.  ypIndex is incremented every time we encounter a new yearNotice how I increment the ypIndex – it is incremented after all the calculations in the new year.  The tradingCapitalAdjustment is then calculated with the latest information.

Here is a table of how the tradingCapital and profit retention adjustment are calculated.  A yearly profit adjustment only takes place after a profitable year.  A losing year passes without adjustment.

All tests were carried out on the trend friendly crude oil futures with no execution costs from 2006 thru 2/28/2204.

See how money is removed from the allocation model after winning years.

Here are some optimization tests with 75% profit retention on yearly and monthly intervals.

Yearly First-

Yearly retention with no stop loss or break-even levels.

Now Monthly-

Monthly retention with no stop loss or break-even levels.

What if we didn’t reallocate on any specific interval?

Huge drawdowns with very little change in total profit.

Add some trade management into the mix.

Here we optimize a protective stop and a break-even level to see if we can juice the results.  All the trade management is on a position basis.

200K with No Reallocating with $14k and $8.5 stop/break-even levels [ranked by Profit Factor]

No position sizing and no reallocation with $5K and $10K stop/break-even levels

200K and monthly reallocating with $7K and $5.5K stop/break-even levels [BEST PROFIT FACTOR]
200K and monthly reallocating with $7K and $8.5K stop/break-even levels [2ND BEST PROFIT FACTOR]

Are we really using our capital in the most efficient manner?

If we retain profit, should we remove some of the loss form the position sizing engine as well.  All the tests I performed retained profit from the position size calculations.  I let the loss go full bore into the calculation.  This is a very risk averse approach.  Why don’t I retain 25% of losses and deduct that amount from the yearly loss and feed that into the position sizing engine.  This will be less risk averse – let’s see what it does.

Not as good.  But I could spend a week working different permutations and optimization sessions.

Are you wondering what Trend Following System I was using as the foundation of this strategy?  I used EasyLanguage’s Linear Regression function to create buy and short levels.  Here is the very simple code.

Value1 = LinearReg (Close, 60, 1, oLRSlope, oLRAngle, oLRIntercept, oLRValueRaw);

Value2 = oLRSlope;

Value3 = oLRAngle;

Value4 = oLRIntercept;

Value5 = oLRValueRaw;


//Basically I am buying/shorting on the change of the linear regression slope
//Also I have a volatility filter but it really isn't used
If value2 >=0 and value2[1] < 0 and avgTrueRange(30)*bigPointValue < 10000 then
buy positionSize contracts next bar at market;
If value2 <=0 and value2[1] > 0 and avgTrueRange(30)*bigPointValue < 10000 then
sellShort positionSize contracts next bar at market;

mp = marketPosition;

//I also have incorporated a 3XATR(30) disaster stop
if mp = 1 and c <= entryPrice - 3 * avgTrueRange(30) then sell next bar at market;
if mp = -1 and c >= entryPrice + 3 * avgTrueRange(30) then buyToCover next bar at market

If you want to see some more Trend Following models and their codes in EasyLanguage and TS-18 Python check out my TrendFollowing Guide and Kit.

Super Trend Indicator in EasyLanguage

SuperTrend Indicator – What Is It?

SuperTrend is a trading strategy and indicator all built into one entity.  There are a couple of versions floating around out there.  MultiCharts and Sierra Chart both have slightly different flavors of this combo approach.

Ratcheting Trailing Stop Paradigm

This indic/strat falls into this category of algorithm.  The indicator never moves away from your current position like a parabolic stop or chandelier exit.  I used the code that was disclosed on Futures.io or formerly known as BigMikesTrading blog.   This version differs from the original SuperTrend which used average true range.  I like Big Mike’s version so it will discussed here.

Big Mike’s Math

The math for this indicator utilizes volatility in the terms of the distance the market has travelled over the past N days.  This is determined by calculating the highest high of the last N days/bars and then subtracting the lowest low of last N days/bars.   Let’s call this the highLowRange.  The next calculation is an exponential moving average of the highLowRange.  This value will define the market volatility.   Exponential moving averages of the last strength days/bars highs and lows are then calculated and divided by two – giving a midpoint.  The volatility measure (multiplied my mult) is then added to this midpoint to calculate an upper band.  A lower band is formed by subtracting the volatility measure X mult from the midpoint.

Upper or Lower Channel?

If the closing price penetrates the upper channel and the close is also above the highest high of strength days/bars back (offset by one of course) then the trend will flip to UP.  When the trend is UP,  then the Lower Channel is plotted.  Once the trend flips to DN, the upper channel will be plotted.  If the trend is UP the lower channel will either rise with the market or stay put.  The same goes for a DN trend – hence the ratcheting.  Here is a graphic of the indicator on CL.

Super Trend by Bike Mike

If you plan on using an customized indicator in a strategy it is always best to build the calculations inside a function.  The function then can be used in either an indicator or a strategy.

Function Name: SuperTrend_BM

Function Type: Series – we will need to access prior variable values

SuperTrend_BM Function Code:

//SuperTrend from Big Mike now futures.io

inputs:
length(NumericSimple), mult(NumericSimple), strength(NumericSimple), STrend(NumericRef);

vars:
highLowRange(0),
xAvgRng(0),
xAvg(0),
dn(0),
up(0),
trend(1),
trendDN(False),
trendUP(False),
ST(0);

highLowRange = Highest(high, length) - Lowest(low, length);

xAvgRng = XAverage(highLowRange, length);

xAvg = (XAverage(high, Strength) + XAverage(low, Strength))/2;

up = xAvg + mult * xAvgRng;
dn = xAvg - mult * xAvgRng;

if c > up[1] and c > Highest(High, strength)[1] then
trend = 1
else
if c < dn[1] and c < Lowest(Low, Strength)[1] then
trend = -1;

//did trend flip?
trendDN = False;
trendUP = False;

if trend < 0 and trend[1] > 0 then
trendDN = True;
if trend > 0 and trend[1] < 0 then
trendUP = True;

//ratcheting mechanism
if trend > 0 then dn = maxList(dn,dn[1]);
if trend < 0 then up = minList(up,up[1]);

// if trend dir. changes then assign
// up and down appropriately
if trendUP then
up = xAvg + mult * xAvgRng;
if trendDN then
dn = xAvg - mult * xAvgRng;

if trend = 1 then
ST = dn
else
ST = up;

STrend = trend;

SuperTrend_BM = ST;
SuperTrend ala Big Mike

The Inputs to the Function

The original SuperTrend did include the Strength input.  This input is a Donchian like signal.  Not only does the price need to close above/below the upper/lower channel but also the close must be above/below the appropriate Donchian Channels to flip the trend,  Also notice we are using a numericRef as the type for STrend.  This is done because we need the function to return two values:  trend direction and the upper or lower channel value.  The appropriate channel value is assigned to the function name and STrend contains the Trend Direction.

A Function Driver in the Form of an Indicator

A function is a sub-program and must be called to be utilized.   Here is the indicator code that will plot the values of the function using: length(9), mult(1), strength(9).

// SuperTrend indicator
// March 25 2010
// Big Mike https://www.bigmiketrading.com
inputs:
length(9), mult(1), strength(9);

vars:
strend(0),
st(0);

st = SuperTrend_BM(length, mult,strength,strend);

if strend = 1 then Plot1(st,"SuperTrendUP");
if strend = -1 then Plot2(st,"SuperTrendDN");
Function Drive in the form of an Indicator

 

This should be a fun indicator to play with in the development of a trend following approach.   My version of Big Mike’s code is a little different as I wanted the variable names to be a little more descriptive.

Update Feb 28 2022

I forgot to mention that you will need to make sure your plot lines don’t automatically connect.

Plot Style Setting

Can You Do This with Just One Plot1?

An astute reader brought it to my attention that we could get away with a single plot and he was right.  The reason I initially used two plot was to enable the user to chose his/her own plot colors by using the Format dialog.

//if strend = 1 then Plot1(st,"SuperTrendUP");
//if strend = -1 then Plot2(st,"SuperTrendDN");

if strend = 1 then SetPlotColor(1,red);
if strend = -1 then SetPlotColor(1,green);

Plot1(st,"SuperTrend_BM");
Method to just use one Plot1

Another Good Year For Trend Following

Take a Look at the Last Two Years

Simple Donchian on a one contract basis.  $100 Commission/slippage.  Tested from 2000 thru December 31, 2021.  Do you see why most trend followers failed after the 2008 monstrous year.   Many funds caught the 2008 move and more funds were added soon thereafter.  Promises of similar performance came to fruition in 2011.  This kept much of the “new money” on the board.  However, reality set in and weak handed funds left for greener pastures.  Those that stuck it out were rewarded in 2014.  The trend drought of 2014 -2019 eroded most of the confidence in managed futures.  The rationalization that limited resources would eventually rise in price sounded good initially, but then fell on deaf ears after months of draw down.  Well known CTAs and hedge funds shut their doors forever.   The long awaited promise of 2008 came in the form of a pandemic – but it was too late.   Maybe now the deluge that ended the drought will persevere (hopefully not in the form of a pandemic) into the future.  Prices do not need to rise endlessly, but they need to move one direction or another without many hiccups.   

Simple Donchian Caught Most of the Commodities Up Moves

Which Sectors Pushed this Curve through the Roof

These reports were generated by my Python based Trading Simula-18 using Pinnacle continuous data – rollover triggered by date.  This is my new sector analysis report where I graph the last four years performance.  The tabular data is for the entire 21 year history.  The best sectors were energy, grains, financials and metals.  Lumber was extraordinary

Sector Analysis Report
################################################
Currency -------------------------------------
BN -28012 44681
SN -26925 55337
AN 6560 34350
DX 16284 24387
FN 67463 31737
JN -22212 50362
CN -25355 44110
------------------------------------------------
Totals: -12198 141445
------------------------------------------------
Currency Last 4 Years ---------------------
|
||| |
||||||
| ||||||||
| |||||||||
| ||||||||||
|||||||||||||
||||||||||||||
|||||||||||||| |
|||||||||||||||||||
||||||||||||||||||||| |
|||||||||||||||||||||| | |
|||||||||||||||||||||| | |
|||||||||||||||||||||| | || | | |
------------------------------------------------ 0
||||||||||||||||||||||||| ||| |||| ||| |
||||||||||||||||||||||||| |||| |||||||||||
||||||||||||||||||||||||| | |||| ||||||||||||
||||||||||||||||||||||||||| |||||||||||||||||
|||||||||||||||||||||||||||| ||||||||||||||||||
||||||||||||||||||||||||||||||||||||||||||||||||
2018--------2019--------2020--------2021--------
################################################
Energies -------------------------------------
ZU 180750 38330
ZH 155696 85541
ZN 70630 74400
ZB 131874 66651
------------------------------------------------
Totals: 538951 154434
------------------------------------------------
Energies Last 4 Years ---------------------
| |
|| || ||
||| || |||
| ||||||||||
| |||||||||||
||| |||||||||||
|||| | ||||||||||||
||||||| ||||||||||||
|||||||||||||||||||||
|||||||||||||||||||||
|||||||||||||||||||||
|||||||||||||||||||||
| || |||||||||||||||||||||
|| || |||||||||||||||||||||
|| |||| |||||||||||||||||||||
||||||||| ||||||||||||||||||||||
| |||||||||| |||||||||||||||||||||||
|| || |||||||||||||||||||||||||||||||||||||
|||||| |||||||||||||||||||||||||||||||||||||
||||||||||||||||||||||||||||||||||||||||||||||||
2018--------2019--------2020--------2021--------
################################################
Metals -------------------------------------
ZG -17070 43540
ZI 68395 146885
ZK 101888 29475
ZP 82885 27600
ZA 174955 83910
------------------------------------------------
Totals: 411052 166703
------------------------------------------------
Metals Last 4 Years ---------------------
|
| | |
|| || |
|| |||| |||
| ||| | |||||||||
|| |||||||||||||||||
|| |||||||||||||||||||
|||||||||||||||||||||||
|||||||||||||||||||||||
|||||||||||||||||||||||
| | ||||||||||||||||||||||||
||||||||||||||||||||||||||||
| ||||||||||||||||||||||||||||||
|| |||||||||||||||||||||||||||||||
|||||||||||||||||||||||||||||||||||
||||||||||||||||||||||||||||||||||||
| |||||||||||||||||||||||||||||||||||||
||||||||||||||||||||||||||||||||||||||||
|| |||||||||||||||||||||||||||||||||||||||||
||||||||||||||||||||||||||||||||||||||||||||||||
2018--------2019--------2020--------2021--------
################################################
Grains -------------------------------------
ZS 79175 20312
ZW -43438 51975
ZC 5238 26688
ZL 13248 24588
ZM 29860 28810
------------------------------------------------
Totals: 84083 88850
------------------------------------------------
Grains Last 4 Years ---------------------
|
|
||
||
|||||||||
|||||||||||
|||||||||||
|||||||||||
||||||||||||
| ||||||||||||
| | ||||||||||||
| || ||| ||||||||||||
||||| ||||| |||||||||||||
|||||||||||| |||||||||||||
|||||||||||| ||| | |||||||||||||
||||||||||||| ||||||| || ||||||||||||||
|||||||||||||||||||||||||||| ||||||||||||||
|||||||||||||||||||||||||||||| |||||||||||||||
||||||||||||||||||||||||||||||| |||||||||||||||
||||||||||||||||||||||||||||||||||||||||||||||||
2018--------2019--------2020--------2021--------
################################################
Financials -------------------------------------
US 35991 24959
TY -350 29175
TU 1473 23969
EC 4700 9650
------------------------------------------------
Totals: 41813 56453
------------------------------------------------
Financials Last 4 Years ---------------------
| | ||||
||| | |||||
||| | || ||||||
||||| ||||||||||
|||||| ||||||||||
|||||||| ||||||||||
|||||||| ||||||||||
||||||||| |||||||||||
||||||||||||||||||||||
| ||||||||||||||||||||||
| ||||||||||||||||||||||
| | ||||||||||||||||||||||
| | || ||||||||||||||||||||||
|| |||||| |||||||||||||||||||||||
||| |||||||||||||||||||||||||||||||
|||| || | |||||||||||||||||||||||||||||||
||||| |||| |||||||||||||||||||||||||||||||
||||||| ||||||||||||||||||||||||||||||||||||
|||||||| ||||||||||||||||||||||||||||||||||||
||||||||||||||||||||||||||||||||||||||||||||||||
2018--------2019--------2020--------2021--------
################################################
Softs -------------------------------------
SB 25927 15035
KC -49775 94069
CC -72140 76660
CT 16785 45470
Lumber 218513 51745
JO 2588 15760
------------------------------------------------
Totals: 141898 128540
------------------------------------------------
Softs Last 4 Years ---------------------
| ||
||||
|||||
|||||
||||||
| ||||||
||||||||
||||||||
||||||||
||||||||
------------------------------------------------ 0
| | |||||||||
| | ||||||||||
||||||||||||||||
||||||||||||||||
|||||||||||||||||
|||||||||||||||||
|| | ||||||||||||||||||
| ||||||||||| | |||||||||||||||||||||
||||||||||||||||||||||||||||||||||||||||||||
||||||||||||||||||||||||||||||||||||||||||||||||
2018--------2019--------2020--------2021--------
################################################
Meats -------------------------------------
ZT -29940 57680
ZZ 38480 15080
ZF 18413 57550
------------------------------------------------
Totals: 26952 66515
------------------------------------------------
Meats Last 4 Years ---------------------
| ||
| || ||
|| | || ||
||| | || ||
||||||||| ||||
| |||||||||| ||||
| | ||||||||||| |||||
| | ||||||||||| |||||| |
| || |||||||||||||||||| |
| ||| | |||||||||||||||||||||
|| ||| | |||||||||||||||||||||
|||||| || | ||||||||||||||||||||| |
|||||| || |||||||||||||||||||||||| |
|||||| || ||||||||||||||||||||||||||
|||||||| | || ||||||||||||||||||||||||||
|||||||| | ||| ||||||||||||||||||||||||||
|||||||||| | |||||||||||||||||||||||||||||||
||||||||||| | |||||||||||||||||||||||||||||||
|||||||||||| || ||||||||||||||||||||||||||||||||
||||||||||||||||||||||||||||||||||||||||||||||||
2018--------2019--------2020--------2021--------

How Do You Program this in Python

Here is the module for TS-18.  There is a little extra code to keep track of sectors in case you want to limit sector exposure.  However, this code takes every trade on a one contract basis.  This code reflects my latest version of TS-18, which will be released shortly.

#  Define Long, Short, ExitLong and ExitShort Levels - mind your indentations
buyLevel = highest(myHigh,40,curBar,1)
shortLevel = lowest(myLow,40,curBar,1)
longExit = lowest(myLow,20,curBar,1)
shortExit = highest(myHigh,20,curBar,1)
ATR = sAverage(myTrueRange,30,curBar,1)
stopAmt = 2000/myBPV

ATR = sAverage(myTrueRange,30,curBar,1)

posSize = 1
mmLxit = 99999999
mmSxit = -99999999
if mp == 1 : mmLxit = entryPrice[-1] - stopAmt
if mp ==-1 : mmSxit = entryPrice[-1] + stopAmt



# Long Exit
if mp == 1 and myLow[curBar] <= mmLxit and mmLxit > longExit and barsSinceEntry > 1:
price = min(myOpen[curBar],mmLxit)
tradeName = "LxitMM"
numShares = curShares
exitPosition(price, curShares, tradeName, sysMarkDict)
unPackDict(sysMarkDict)
# Long Exit
if mp == 1 and myLow[curBar] <= longExit and barsSinceEntry > 1:
price = min(myOpen[curBar],longExit)
tradeName = "Lxit"
numShares = curShares
exitPosition(price, curShares, tradeName, sysMarkDict)
unPackDict(sysMarkDict)
# Short Exit
if mp == -1 and myHigh[curBar] >= shortExit and barsSinceEntry > 1:
price = max(myOpen[curBar],shortExit)
tradeName = "Sxit"
numShares = curShares
exitPosition(price, curShares, tradeName, sysMarkDict)
unPackDict(sysMarkDict)
# Short Exit
if mp == -1 and myHigh[curBar] >= entryPrice[-1] + stopAmt and barsSinceEntry > 1:
price = max(myOpen[curBar],entryPrice[-1] + stopAmt)
tradeName = "SxitMM"
numShares = curShares
exitPosition(price, curShares, tradeName,sysMarkDict)
unPackDict(sysMarkDict)
# Long Entry
if myHigh[curBar] >= buyLevel and mp !=1:
price = max(myOpen[curBar],buyLevel)
tradeName = "Simple Buy"
numShares = posSize
enterLongPosition(price,numShares,tradeName,sysMarkDict)
unPackDict(sysMarkDict)
# Short Entry
if myLow[curBar] <= shortLevel and mp !=-1 :
price = min(myOpen[curBar],shortLevel)
if mp == 0 : sectorTradesTodayList[curSector] +=1
tradeName = "Simple Sell"
numShares = posSize
enterShortPosition(price, numShares, tradeName, sysMarkDict)
unPackDict(sysMarkDict)
Python within Trading Simula-18