The smallest strategy that is not lying to you
Most first-strategy tutorials start with strategy("My Strategy") because it
is short. That version reports profits from a market that charges nothing to
trade, and the habit is hard to unlearn. Four extra arguments fix it.
//@version=6
strategy("First strategy", overlay = true,
initial_capital = 10000.0,
commission_type = strategy.commission.percent,
commission_value = 0.1,
slippage = 3,
default_qty_type = strategy.fixed,
default_qty_value = 1)
fastLen = input.int(20, "Fast MA length", minval = 1)
slowLen = input.int(50, "Slow MA length", minval = 1)
fast = ta.sma(close, fastLen)
slow = ta.sma(close, slowLen)
if ta.crossover(fast, slow)
strategy.entry("Long", strategy.long)
if ta.crossunder(fast, slow)
strategy.close("Long")
plot(fast, "Fast", color = color.blue)
plot(slow, "Slow", color = color.orange)
That is a complete, honest strategy. Everything below is why each line is the way it is.
Why the indicator calls sit outside the if
fast and slow are computed at the top level, not inside the conditions.
This is not style. In v6 the and and or operators evaluate lazily [2], so a
ta.* call placed after a condition that is false gets skipped on that bar
— and an indicator that did not run on every bar no longer has a continuous
history.
Hoisting them is the fix, and it is the single most common defect in AI-generated and copied Pine. The detail is in the v6 changes that do not error.
Why the lengths are input.int and not variables
ta.sma() wants its length as a simple int, and anything computed from price
would be series, which is stronger in the qualifier hierarchy and therefore
rejected [3]. input.int() produces an input int, which is weaker and
accepted. This is the error that confuses everybody once —
why Pine is hard explains what
the engine actually needs.
minval = 1 is not decoration either: a length of zero or a negative length is
meaningless, and constraining it in the declaration is cheaper than handling it
in the logic.
Why strategy.fixed and not percent of equity
strategy.fixed trades a constant size, so the equity curve does not
compound [1]. strategy.percent_of_equity compounds, which makes a mediocre
edge look dramatic over a long backtest.
For a first strategy you are asking "does this idea work", not "what would this have grown to". Fixed size answers the first question and is the harder test to pass.
Why strategy.close() instead of an exit price
The exit here is the opposite signal, not a stop or a target. That keeps the first version to one decision — when to be in — rather than three. Stops and targets bring in the emulator's rule about which level a bar hit first, and that is worth understanding before you depend on it: risk management.
Six decisions you just made without knowing
A working first strategy answers about six questions you were never asked. They are all defaults, they all change your results, and none of them is visible in the code you wrote.
| Question | What was decided for you | Where |
|---|---|---|
| How many positions may be open at once? | one — pyramiding defaults to 1 [1] | the declaration |
| Is margin enforced? | yes since v6 — margin_long and margin_short default to 100 [2] | the declaration |
| When does the order actually fill? | on the next bar's open, not the signal bar's close | the emulator |
| How much history is tested? | as much as your account plan allows [4] | your subscription |
| What timeframe is this strategy for? | whatever chart you happened to attach it to | the chart |
| Which instrument is the slippage calibrated for? | the one you tested on — a tick is a different size elsewhere | nothing records it |
The two with money attached
pyramiding defaults to 1 [1]. So when your entry condition fires again
while a position is open, nothing happens. That is usually what you want, and it
is also the answer to "why did my second entry not appear" — the condition was
fine; the declaration silently declined.
Margin is now enforced. Since v6, margin_long and margin_short default
to 100, and a strategy that needs more money than is available does not open
the entry [2]. A strategy ported from v5 will therefore take fewer trades —
no error, just a shorter trade list. The v6 default is the more honest of the
two, and worth keeping.
The one that is not a default at all
Nothing in Pine records which instrument or timeframe a strategy was built for. The chart decides, and the chart can be changed after the fact by anyone.
This is why slippage = 3 is a claim about one instrument rather than a
setting: slippage is counted in ticks, and a tick is not the same size on two
symbols. Move the script to another market and that number quietly means
something else — the commonest reason a sound strategy stops working, and the
one least often discussed:
why copied scripts fail.
Write the intended instrument and timeframe in a comment at the top. It costs one line and it is the only place that information can live.
What to change first, once it runs
In this order, because each one can make the next irrelevant:
- Costs, if you have not already — everything downstream is measured through them
- The date range, to something you did not pick because it looked good
- A second instrument, which tests whether you built a strategy or fitted one market
- The parameters, last — and if you try several, the count of how many is part of your result: why that matters
Most people do these in exactly the opposite order, which is why most first strategies look excellent and do not survive contact with a second symbol.
Tactix AI — Studio vs Guide
Tactix AI is AlfaTactix’s product assistant brand (open Tactix AI).
- Tactix Studio turns a one-sentence strategy description into a draft across Timeframe, Signals, Filters, and Risk in the visual Strategy Builder. You review and edit every field before Code Generator writes MQL5 or Pine Script.
- Tactix Guide explains the step you are on — what to fill, what a control means, or how to phrase a rule — without dumping untested source code.
That is form-first automation: the LLM never replaces Code Generator, and you keep plan limits and real-time validation.

