LSE GTT Order Expiry Verification
Overview
In this example, CodeLogician is used to discover a critical bug in an enhanced (by Imandra) version of the London Stock Exchange trading system specification — a subtle race condition that would likely escape traditional testing but could result in exchange violations.
The Bug: MIT201 Specification Violation
Found: GTT orders can expire simultaneously with auction uncross events, violating design requirements.
Impact: Orders incorrectly excluded from auctions they should participate in.
Detection: Traditional testing missed this edge case—formal verification found it immediately with a concrete counterexample.
The Business Requirement
The publically available London Stock Exchange Guide to the Trading System (MIT201) specifies:
MIT201 Specification
"Any GTT orders with an expiry time during any auction call phase will not be expired until after uncrossing has completed and are therefore eligible to participate in that uncrossing."
This is a critical requirement. Violating it means:
- ❌ Incorrect order handling during auctions
- ❌ Potential customer losses and complaints
- ❌ Exchange compliance violations
- ❌ Reputational damage
The System
Model Components
The trading system implementation (384 lines of Python) includes:
Trading Modes
- Continuous: Normal trading hours
- Auction Call: Pre-auction phase with scheduled uncross
GTT Orders
- Good Till Time: Orders with expiry timestamps
- Auction Protection: Delay expiry during auctions
Market Order Extension
- Extension Period: Auction if market orders remain
- Effective Uncross: Original time + extension
Verification Function
- conflict_reachable: Detects simultaneous events
- Property: Uncross and Expiry should be impossible
The Bug Discovery
CodeLogician's Counterexample
Initial State (t=2699)
state = {
time: 2699,
mode: AuctionCallMode { uncross_at: 2700 },
gtt_order: Some { expires_at: 2700 },
market_order_present_after_uncross: true, ← Critical!
market_order_extension_period: 1
}
messages = [Tick, Tick]Timeline Visualization
💥 The Conflict
t=2701:- Auction uncrosses (because 2701 ≥ 2700 + extension(1))
- GTT order expires (because 2701 ≥ extended_expiry(2701))
- Result: Both events occur simultaneously—MIT201 violation!
Why Traditional Testing Misses This
- Requires exact timing alignment of order expiry, auction uncross, and market order extension
- Bug only manifests when
extension_period = 1(would need exhaustive testing) - Individual features work correctly—bug emerges from feature interaction
- Formal verification explores all possible states automatically
Value Demonstrated
Automated Discovery
- ✓ No manual test case writing
- ✓ Exhaustive analysis of all executions
- ✓ Concrete counterexample with exact values
- ✓ Identified specific fix location
Regulatory Compliance
- ✓ Mathematical guarantee of rule compliance
- ✓ Evidence for auditors and regulators
- ✓ Protection against edge cases
- ✓ Documentation of guaranteed behavior
Design Validation
- ✅ Individual features work correctly
- ❌ Feature interaction had bug
- ✅ Verification caught it immediately
- ✅ Clear guidance for fix
Business Impact
❌ Without Formal Verification
- Manual test case design: Days
- May miss edge cases: Likely
- Bug found in production: Weeks/Months later
- Regulatory penalty: $$$
- Customer compensation: $$$
- Reputational damage: Priceless
Risk: Hidden bugs can escape to production, causing regulatory violations and financial losses.
✅ With CodeLogician
- Formalization: Minutes (automated)
- Verification: Minutes (automated)
- Bug discovery: Immediate
- Fix validation: Minutes (re-verify)
- Production incidents: Zero
- Customer confidence: Maintained
Guarantee: Mathematical proof that critical properties hold for ALL possible inputs.
Step-by-Step: Using CodeLogician
Expand: How to Verify Your Trading System
Step 1: Model Your System in Python
Create a clean Python model with your business logic:
from dataclasses import dataclass
from enum import Enum
from typing import Optional, List
# Define your types
class TradingMode(Enum):
CONTINUOUS = "continuous"
AUCTION_CALL = "auction_call"
@dataclass
class State:
time: int
mode: TradingMode
# ... other fields
# Define state transitions
def process_tick(state: State) -> State:
# Your business logic here
pass
# Define verification property
def conflict_reachable(messages: List, state: State) -> bool:
"""Check if bad state is reachable."""
final_state = run(state, messages)
return bad_condition_holds(final_state)Step 2: Initialize CodeLogician
from code_logician import create_thread, init_state
# Create a verification thread
thread_id = create_thread()
# Load your Python code
with open("your_model.py", "r") as f:
src_code = f.read()
# Initialize formalization
init_state(thread_id, src_code=src_code, src_lang="python")Step 3: Automated Formalization
from code_logician import agent_formalizer
# Run automatic Python → IML transformation
result = agent_formalizer(thread_id, no_refactor=False)
# Check formalization status
if result["status"] == "TRANSPARENT":
print("✅ Model fully formalized")
else:
print("⚠️ Manual review needed")Step 4: Generate Verification Goals
from code_logician import gen_vgs
# Describe what you want to verify
gen_vgs(
thread_id,
description="""
Verify that the critical business property holds:
For all valid initial states and message sequences,
the conflict_reachable function should return false.
Specifically:
1. Check that valid states exist (VG1)
2. Prove that conflict is impossible (VG2)
"""
)Step 5: Analyze Results
CodeLogician will generate and check verification goals:
Case 1: Property Holds ✅
VG2: PROVED
∀ msgs, s: is_valid_state s ⟹ ¬(conflict_reachable msgs s)
No counterexample exists. Property is guaranteed.
Case 2: Bug Found ❌
VG2: REFUTED
Counterexample:
msgs = [Tick, Tick]
s = { time: 2699, mode: Auction {...}, ... }
This scenario violates the property!
Step 6: Fix and Re-verify
If a bug is found:
- Analyze the counterexample - Understand the scenario
- Identify root cause - Why does the bug occur?
- Implement fix - Update your Python code
- Re-run verification - Confirm fix with mathematical proof
# Update your model with the fix
# Then re-verify
init_state(thread_id, src_code=fixed_code, src_lang="python")
agent_formalizer(thread_id)
gen_vgs(thread_id, description="Same VG - verify fix works")
# Expected: ✅ PROVED (no counterexample)Key Insights
Iterative Process:
Verification often finds bugs. That's the point! Fix them iteratively with concrete counterexamples guiding you.
Mathematical Certainty:
When verification succeeds, you have proof—not just confidence—that your property holds for ALL inputs.
CI/CD Integration:
Add verification to your pipeline to catch regressions automatically before they reach production.
Resources
Download the Example
Key Takeaways
Real Bug Discovery
Automated Analysis
No manual test writing—exhaustive analysis of all possible executions.
Concrete Scenario
Exact counterexample with initial state values and message sequence.
Clear Fix
Feature Interaction
Bug emerged from interaction of two independently correct features.
Financial Domain
Verify your critical trading systems
Discover bugs before they reach production. Get mathematical proof of correctness.