Python Subset
תוכן זה אינו זמין עדיין בשפה שלך.
RaamCode is a strict subset of Python. Most everyday constructs work. A handful of categories don’t — and they don’t for specific reasons.
What works
Control flow
if condition: passelif other: passelse: pass
for i in range(n): ...
for x in self.some_list: # a class-body-declared list pass
for k in self.some_dict: # yields KEYS passpass is the empty-body placeholder. Python’s ... (Ellipsis) is not a statement RaamCode accepts — it raises RC2_EXEC_STMT.
No while, no break / continue, no for … else. range() takes one or two arguments — the three-argument stepped form is refused. Iteration over a list or dict works only for a persistent-state collection declared in the class body; there are no ad-hoc lists. See For Loops.
Arithmetic and comparison
x = a + b * c / dy = (a + b) % cz = a ** 2result = max(a, min(b, c))
# Comparisonsa == b, a != b, a < b, a > b, a <= b, a >= bAll arithmetic on indicator values and OHLCV happens in decimal precision — never float. Mixing types (e.g., decimal * float) is allowed; the result stays in decimal.
Logical operators
a and ba or bnot aShort-circuit semantics are preserved (same as Python).
Built-in functions
int(x), float(x), bool(x)abs(x), min(a, b), max(a, b), round(x), round(x, ndigits)len(self.my_list), len(self.my_dict)print(...)min and max need at least two arguments — min(x) is RC2_BUILTIN_ARG.
len() in a strategy works only on a persistent-state list or dict declared in the class body. Inside a custom indicator’s compute(), len(self.buffer) and sum(self.buffer) work on Series objects — sum is an indicator-side builtin and is not available in strategy code.
Series scans — custom indicators only. These take a declared self.<series> and exist nowhere else; a strategy has no Series-shaped value to hand them, so calling one there is a compile error, not a surprise at run time:
sum(self.buffer), min(self.buffer), max(self.buffer)stddev(self.buffer)median(self.buffer)percentile(self.buffer, p) # p in 0-100rank(self.buffer, x) # the fraction strictly below x, 0-1See Custom indicators → Series API for what each answers, including the empty-window and even-window rules.
math.* needs no import: math.sqrt, math.log, and the rest of the standard library are ambient. Writing import math is RC2_IMPORT_BLOCKED, with a message saying exactly that.
F-strings
reason = f"RSI is {rsi.value:.1f}, position={self.trade.position}"self.buy(self.trade, reason=reason)Supported format specs: .Nf, .Ne, .Ng, .N%, d, x, X. Anything else — alignment and padding like :>10, thousands separators like :,.2f, explicit signs like :+.2f — raises the warning RC2_FSTRING_SPEC: the strategy still compiles, and the value is interpolated with no formatting applied.
Ternary expressions
size = 100 if self.trade.close > 50 else 50What’s blocked
| Construct | Why |
|---|---|
import anything |
No external code. The transpiler can’t reason about what’s inside someone else’s module. |
try, except, finally, raise |
Error handling is the platform’s responsibility. Letting strategies catch and suppress errors hides bugs. |
async, await, yield |
Strategies are pure functions of bar data. Concurrency doesn’t belong here. |
with (context managers) |
All resources are platform-managed. There’s nothing user-level to enter / exit. |
lambda |
Eliminates entire classes of escape mechanism (callable values capturing scope). |
global, nonlocal, del |
State management is bounded. These three break that bound. |
eval(), exec(), open() |
Dynamic-code execution and file I/O are out of scope. |
| Tuples as state | Lists and dicts are supported as persistent state, but only when declared in the class body with a literal (see Persistent State). Tuples are not, and no collection may be built ad hoc inside execute(). |
Each blocked construct emits a specific diagnostic. See the Error Reference.
print(...) is allowed
Use print(...) in your strategy code exactly like in plain Python — print(*objects, sep=' ', end='\n') (the file= and flush= kwargs are accepted for paste compatibility and ignored). Captured output appears in the Console tab on the run board (during a backtest) or the Log tab (on a live runner). One print(...) call = one row.
class Instrumented(Strategy): trade = Symbol() sizing = FixedCapital()
def execute(self): rsi = RSI(14, on=self.trade) if rsi.crossed_above(70) and self.trade.is_long: print("RSI overbought at", self.trade.close) self.sell(self.trade, self.trade.position)print is silent on the optimizer’s fast path
print(...) does not slow a strategy down — it keeps the analyzed fast path. But the graph body that path emits contains no print call at all, so an optimization or walk-forward run produces no output. Instrument with print while backtesting; do not expect it during a sweep.
print(...) works in execute() and on_update_indicators(). It is suppressed when used inside a custom indicator’s compute() method (the value is cached across runs, so the call would not re-fire). Each captured row carries the bar timestamp it fired on.
Why a subset?
Three reasons:
- Determinism. A strategy must produce identical results in backtest, paper, and live. Anything that can vary based on the environment (network, files, randomness) breaks that.
- Isolation. Thousands of strategies run on shared infrastructure. Nothing escapes its own sandbox — and the easiest way to guarantee that is to refuse imports and I/O at compile time, not at runtime.
- Reviewability. A strategy that’s a few classes, a few methods, and arithmetic is easy to read. A strategy that pulls in arbitrary dependencies is not.
The subset is large enough that almost any trading idea fits. If yours doesn’t, open an issue — most “I need X” requests turn out to fit through an existing primitive once we look together.
Common diagnostics
| Code | What it means |
|---|---|
RC2_IMPORT_BLOCKED |
import statement found. |
SDK012 |
Blocked built-in called (eval, open, etc.). |
RC2_EXEC_STMT |
Disallowed statement type in execute() — try, with, while, raise, or a bare .... |
RC2_FSTRING_SPEC |
An f-string format spec the transpiler can’t translate. Warning only. |
RC2_BUILTIN_ARG |
A builtin called with the wrong arguments. |