Project: An Event-Driven DAS Spread Observer
Implement initialization, sampling, hysteresis, manual reporting and stop controls.
Project specification
Prerequisites: timers, state machines and quote validation. Observe one preloaded symbol and count transitions into a hypothetical spread condition. No direction, entry or exit decision is produced. Four manual operations define the lifecycle: initialize, install callback, inspect, stop. A lower reset threshold creates hysteresis and prevents repeated reports around a single boundary.
Initializer: run with Timer disabled
$feSpreadWatch = NewUserObj();
$feSpreadWatch.symbol = "MSFT";
$feSpreadWatch.trigger = 0.08;
$feSpreadWatch.reset = 0.05;
$feSpreadWatch.enabled = 1;
$feSpreadWatch.latched = 0;
$feSpreadWatch.valid = 0;
$feSpreadWatch.reports = 0;
$feSpreadWatch.lastSecond = GetSecond();
$feSpreadWatch.spread = 0;
Timer Event callback
if ($feSpreadWatch.enabled == 0) {
return;
}
$feSpreadWatch.valid = 0;
$feWatchQuote = GetQuoteObj($feSpreadWatch.symbol);
$feWatchBid = $feWatchQuote.BID;
$feWatchAsk = $feWatchQuote.ASK;
if ($feWatchBid <= 0) {
return;
}
if ($feWatchAsk < $feWatchBid) {
return;
}
$feWatchNow = GetSecond();
if ($feWatchNow < $feSpreadWatch.lastSecond) {
$feSpreadWatch.enabled = 0;
return;
}
$feSpreadWatch.spread = $feWatchAsk - $feWatchBid;
$feSpreadWatch.lastSecond = $feWatchNow;
$feSpreadWatch.valid = 1;
if ($feSpreadWatch.spread > $feSpreadWatch.trigger) {
if ($feSpreadWatch.latched == 0) {
$feSpreadWatch.latched = 1;
$feSpreadWatch.reports = $feSpreadWatch.reports + 1;
}
}
if ($feSpreadWatch.spread < $feSpreadWatch.reset) {
$feSpreadWatch.latched = 0;
}
Manual inspection and stop
$feSpreadWatch.ShowObject();
$feSpreadWatch.enabled = 0;
Explain the recovery rules
Invalid numerical input sets valid=0 and does not fabricate a new spread. It leaves the previous spread visible as historical state, so consumers must check valid. A backward clock disables the observer and requires reinitialization. Equality with either threshold leaves the latch unchanged. Initialization sets latched=0, so startup already above trigger will count once. If that is not desired, implement a separate initial-baseline state. Object lookup errors are not caught by this example; preloading and verifying the symbol remain prerequisites.
Deterministic acceptance sequence
Before live quote observation, replace the two quote reads in a test copy with fixed Bid=20 and Ask values producing spreads 0.04,0.09,0.10,0.06,0.04,0.09. Execute one callback per sample after one initialization. Expected report counts: 0,1,1,1,1,2. The 0.06 sample does not reset the latch because reset is below 0.05. Then test zero Bid, inverted quotes and a backward time value. Restore real reads only after the model behaves correctly.
Extension exercise and worked answer
Add a lastReportSecond field. Answer: initialize it to zero and update it only inside the 0→1 transition branch. Do not update it on every valid sample. Connect an optional message-only Alert to a dedicated published event counter after verifying variable-trigger behavior. To remove the project, disable the DAS Timer callback first, then clear its state.