Category Archives: Theory

Why EasyLanguage Should Be the Blueprint for Quant Languages

When I first ran into EasyLanguage, I didn’t take it seriously.

I come to this with a bias: I’m a lifelong systems programmer, and I helped build a trading platform the old-fashioned way.

Years ago I co-created Excalibur, a Fortran-based trading and backtesting engine. In that world, everything is explicit. If you want rolling windows, you build them. If you want indicator “memory,” you write the storage. If you want speed, you earn it with careful code and a lot of scaffolding.

So when I first encountered EasyLanguage, I didn’t take it seriously. It looked too simple—almost like “training wheels” for people who didn’t want to program.

Then time did what time always does: it changed my opinion.

After decades of building systems, libraries, and tooling—and watching how often good ideas get buried under boilerplate—I started to see EasyLanguage differently. It’s not “cute.” It’s a purpose-built quant DSL with one superpower that most general-purpose languages don’t give you for free:

Native time-series semantics.

In other words, EasyLanguage starts you in a world where “one bar ago” is normal, rolling windows are natural, and stateful indicators can be expressed as simple algebra. If I were building a quant language today, I’d copy that blueprint: human-readable rules plus time-series semantics baked into the language.

To explain why, I like a metaphor: Flatland versus Spaceland.


Flatland versus Spaceland

Flatland is where most beginners start—especially if they come from C, Python, or Excel. In Flatland, a variable is simply “a value right now.” The world feels perfectly sensible, but it’s missing something. The moment you need yesterday, or the last 30 bars, you’re forced into extra machinery: arrays, indexing, loops, buffers, bookkeeping.

Then comes the EasyLanguage moment—the part that feels like science fiction the first time you truly get it.

In Spaceland, the “missing dimension” exists: time. Variables don’t just have a current value; they have a built-in past. Close naturally includes Close[1]. Your own variables remember prior values. Rolling functions like Average() and RSI() aren’t special libraries—they’re native operations on values that already extend through time.

So the breakthrough isn’t learning a new function. It’s realizing you’ve been thinking on a plane, and EasyLanguage is operating in a world with one more dimension.

(If you’ve never read Edwin Abbott’s novella Flatland, no worries—this post borrows the idea, not the geometry. Abbott’s missing dimension is spatial; mine is time.)


Scalar versus series (without the esoterica)

In most general-purpose languages, a variable is a scalar: one value right now. If you want the last 30 values, you must store them and manage the indexing yourself.

In EasyLanguage, variables behave like series: the current value plus an implicit history. That’s why these feel natural:

If Close > Close[1] then ...
value1 = Average( (High + Low) / 2, 30 )
value2 = Average( RSI(Close, 14), 30 )

The “series prep” tax in Python

EasyLanguage can do this in one line because it can treat the expression (High + Low)/2 as a time series automatically:

MidPointAvg = Average((High + Low)/2, 30)

In Python—even if high and low already exist as lists—you still have to manufacture the series you want to average. Before you can average midpoints, you must first create a new midpoint list for the last lookBack bars:

# Assume:
# - high and low are lists (oldest -> newest)
# - currentBar is the index of the bar we're on "right now"
# - lookBack is how many bars we want to include
lookBack = 30

# Step 1) Build a NEW series (midpoint) for the last lookBack bars
midpointSeries = []

for barsAgo in range(lookBack):
bar = currentBar - barsAgo
if bar < 0:
break # ran out of history

midpoint = (high[bar] + low[bar]) / 2.0
midpointSeries.append(midpoint)

# Step 2) Now we can feed that newly created series to the generic average
mid_avg = average(midpointSeries)

Same goal. Totally different assumptions.

  • Python is scalar-first: you build the series.

  • EasyLanguage is series-first: the platform quietly supplies the time dimension.

Why EasyLanguage is a great engineering-to-trading bridge

If you’re coming from DSP or any engineering intensive discipline, you already know what you want to test: filters with memory, rolling statistics, trigger lines, crossings, parameter tweaks you can validate visually. The last thing you want is to burn weeks building infrastructure—buffers, indexing rules, warm-up handling—before you ever test the idea. EasyLanguage skips that entire tax. It starts you in Spaceland: time-series semantics are native, history is built in, and writing a filter looks like writing the math.

The mind-meld example (Ehlers High Pass)

Here’s a (simplified) EasyLanguage high-pass filter. From a programmer’s perspective, it’s mind-bending because it reads like algebra, but behaves like a stateful filter:


//Ehlers HighPass function - from his website
//https://www.mesasoftware.com/papers/

Inputs: Price(NumericSeries), Period(NumericSimple);


Vars: a1(0),
b1(0),
c1(0),
c2(0),
c3(0);

a1 = ExpValue(-1.414*3.14159 / Period);
b1 = 2*a1*Cosine(1.414*180 / Period);
c2 = b1; c3 = -a1*a1;
c1 = (1 + c2 - c3) / 4;
If CurrentBar >= 4 Then
EhlersHighPass = c1*(Price - 2*Price[1] + Price[2]) +
c2*EhlersHighPass[1] + c3*EhlersHighPass[2];
If CurrentBar < 4 Then
EhlersHighPass = 0;

The “magic” is here:

c2*EhlersHighPass[1] + c3*EhlersHighPass[2]

In computer-science terms, this is not “recursion” (no function calls itself). In signal-processing terms, it’s feedback: today’s output uses prior output. EasyLanguage makes that look effortless because the platform runs once per bar and preserves the prior values automatically.


Brain Meld Squared

If you’re a programmer, you know what kind of scaffolding this should require:

value1 = EhlersHighPass(Close, 14);
value2 = EhlersHighPass(Close, 28);

Those are two independent filters. Each one needs its own private memory—its own prior outputs—yet EasyLanguage gives you two clean calls. No objects. No buffers. No state management. It just works.


Ultra special: chaining filters

And if you can do that, you can do this:

value1 = EhlersHighPass(EhlersHighPass(Close, 14), 20);

That single line implies two live filter instances with separate state, running bar-by-bar, with the outer filter consuming the inner filter’s output as a time series. That’s series semantics and object-like behavior showing up at the same time—without the programmer ever building the scaffolding.


Closing thought

If I were designing a quant language today, I’d copy EasyLanguage’s blueprint: human-readable rules plus native time-series semantics. It lowers the barrier for non-programmers and removes the infrastructure tax for engineers who just want to test ideas quickly—especially the DSP-to-trading crowd.

Mean Reversion in 5 lines of code:

input: mDay(0),nDay(1),stopLossAmt$(1750),profitTargAmt$(5000),tradeLife(5);

if close > average(close,100) and close mDay days ago < close mDay + nDay days ago then
buy next bar at market;
if barsSinceEntry > tradeLife then sell next bar at open;

setStopLoss(stopLossAmt$);
setProfitTarget(profitTargAmt$);
Could be written as 5 lines, right?

Results

Simple EasyLanguage Code
This POINT is AVERAGE of 66 Values

All points that start with the address 2, 4 were all positive.  There were 66 observations.

66 addresses @ MDAY = 2 AND NDAY = 4

Splicing away all but MDAY = 2!  Big BLOBS.  Some were good (green) and some were bad (purple!)

Volumetric SLICED @ MDAY = 2

Magnifying the blobs – they break away into 6 distinct values – 4 dimensions in 3D Space.

Entering the MATRIX 4 Parameters plotted in 3 Dimensional

These graphs demonstrate a certain level of robustness.   As long as we stay in a bull market to a certain degree.