Why the builder refused that connection
A wire that will not drop is annoying, and it is more useful than it looks. Every refusal in the canvas corresponds to something that would otherwise compile into an EA and misbehave quietly. Here is the whole list.
The rules, in one table
| The message | What it means | What to do |
|---|---|---|
| Data type mismatch | A number is being fed to a boolean input, or the reverse | Put a comparison node between them |
| This input only allows one connection | Inputs take exactly one edge | Delete the existing wire first, or use a logic node to combine |
| Only a Variable node can be connected here | An assignment must name a declaration | Wire the Variable node's ref output |
| An event starts the flow — it is not a condition to combine | An event is being fed into AND/OR/NOT | Wire the conditions into the logic node instead |
| This connection would create a cycle | The graph would feed back into itself | Store the value in a Variable and read it next tick |
| Source handle must be an output | Two inputs or two outputs | Drag from a port on the right of a node to one on the left |
Port types
Every port carries a type, and the dot is coloured by it. There are four:
- numeric — an indicator value, a price, a parameter, a math result.
- boolean — a condition's answer, and what a trading node's trigger wants.
- any — for ports that genuinely accept either, such as a comparison's two sides.
- variableRef — a place to store a value, not a value.
variableRef is the odd one, and it is checked before the "any goes with
anything" rule rather than after. Without that exception a global parameter's
untyped output would satisfy an assignment target, and you would have an EA
assigning to something that is not a variable.
The rule to internalise: an indicator does not connect to a Buy node. RSI produces a number and a Buy node wants a yes or no. The comparison node in between is not ceremony, it is where you say what about the RSI should cause a trade.
One edge per input, with one exception
Inputs take exactly one connection. Outputs can feed as many places as you like.
The exception is the end-of-handler nodes — On Tick End and On New Candle End — which accept any number. An end node is where the handler returns, and a real strategy reaches it down more than one path: the long branch, the short branch, and the branch that decided to do nothing all finish there. With a single-edge port only one of them could say so, and the others would run off the end of the graph with nothing marking them as terminated.
If you need two things to feed one input, that is what the AND and OR nodes are for. They declare how many inputs they have (two to six), and wiring can raise that count but never lower it — the count is your declaration, and the stepper refuses to drop below the highest input you have actually wired rather than orphaning an edge.
An event is not a condition
"On Tick AND rsi > 70" is not a thing you can say, and the builder says so rather than letting it through.
An event is control flow — it is what makes the question worth asking, not
half of the question. This is a structural rule rather than a type, and the
reason is worth stating because it looks like an inconsistency: an
if-condition's true output is genuinely both a value (feed it to an AND) and
a trigger (feed it to a Buy). Typing events as their own thing would force the
order trigger to be that thing too, and break the single most common edge in
the app. So the narrow rule states the one nonsense case instead of inventing
a type the schema cannot support.
No cycles
A connection that would create a loop is refused, because the generated code would need a value that does not exist yet.
If you want this tick's decision to depend on last tick's value, that is what a Variable node is for: write to it at the end of the handler, read from it at the start of the next one. The loop happens in time, where it belongs, instead of in the graph.
Ids drive logic; labels are decoration
Underneath all of this is one rule that explains most of the app's behaviour: an edge stores node ids and port ids. Never a label.
So renaming things is always safe. Rename a custom indicator's output from "Upper band" to "Resistance" and every wire stays put. Rename the node itself and nothing moves. There is no operation in the builder where changing a piece of text you read on screen rewires a strategy.
The corollary is that a port which does not exist cannot be wired to. When a graph is loaded, an edge pointing at an unknown port is dropped rather than guessed at — failing closed, because the alternative is an edge that quietly attaches to the wrong thing.
Deleting is also a graph operation
Deleting a node removes the edges attached to it, because a dangling edge fails validation the next time the project loads.
It also re-runs the synchronisation pass, which matters more than it sounds. Delete the wire feeding a Buy node's Lot Size port and the node goes back to using its typed lot — it does not sit there claiming to be wired with no wire attached. The same applies to every port that can be either typed or fed: unplugging always restores the value that was underneath.
When a refusal is the cheapest thing that happens
The canvas refuses what it can see. A second set of checks runs before an export, and refuses things that are only knowable at that point: an indicator your target platform does not ship, an assignment with nothing connected to it, a parameter name that is not a legal identifier, a custom indicator compiled for the other terminal.
Both of those happen before anything is spent on generating code, and each names the node responsible. Finding out in MetaEditor instead is a slower way to learn the same fact. If you are new to the canvas, the overview of how the graph becomes code is the place to start.
Keep reading
How to build a MetaTrader Expert Advisor without writing MQL
A node graph is a program. Here is what each node type does, how the connections become code, and what you get when you press export.
4 min readEvery indicator parameter can be a wire, not a typed-in number
An RSI period does not have to be 14 forever. Wire it to a global parameter and it becomes tunable in the terminal — and optimisable later — without touching the graph.
3 min readHow to size a position from account balance, not a fixed lot
A hardcoded 0.1 lot means something different on every account. Here is how to read balance, tick value and the broker's own limits into the graph and size a trade from them.
6 min read