Synthetische controlemethoden voor het evalueren van handelsstrategieën
Deze serie heeft lange tijd op één route naar een valse voorsprong doorgebracht: selectie. The Deflated Sharpe Ratio prijst de winnaar van een zoekopdracht. The Probability of Backtest Overfitting prijst de zoekopdracht zelf. Het eerlijke negatieve is wat er gebeurt als je beide naar een strategie wijst waarin je eigenlijk wilde handelen. Dat apparaat beantwoordt één vraag goed: heb ik dit gevonden omdat ik te vaak keek?
Het raakt niet aan een tweede, geheel aparte route: verwarrend. Je veranderde één ding – implementeerde een nieuw uitvoeringsalgoritme, veranderde een parameter, reageerde op een regime – en de prestaties verbeterden. Er werd niet gezocht. Er was geen probleem met meerdere tests. En de verbetering heeft misschien nog steeds niets met u te maken, omdat de volatiliteit verdubbelde in de week dat u verscheepte. Geen enkele hoeveelheid deflatie vangt dit op, omdat deflatie corrigeert voor pogingen en je er maar één hebt uitgevoerd.
De Synthetic Control Method (SCM), ontwikkeld door Abadie en Gardeazabal (2003) en verfijnd door Abadie, Diamond en Hainmueller (2010, 2015), valt direct verwarring aan. Het construeert een contrafeitelijk – een gewogen combinatie van instrumenten die u niet hebt aangeraakt, zo gekozen dat het behandelde instrument vóór de interventie nauwgezet werd gevolgd. Het verschil tussen de twee na de interventie is uw effectschatting. Cruciaal is dat SCM wordt geleverd met een falsificatiecriterium dat u vertelt wanneer het geen geloofwaardig contrafeitelijk resultaat kan opleveren, en een op permutatie gebaseerde p-waarde waarbij u niet in een asymptotisch verhaal hoeft te geloven.
Waarom de voor de hand liggende alternatieven mislukken

Voor-na-vergelijking verwart de interventie met al het andere dat op die datum veranderde. Vergelijking met een enkel benchmarkinstrument mislukt omdat geen enkel instrument de jouwe volgt. Dit is de Single Instrument Trap vanuit de andere richting: als de idiosyncratische structuur van het ene instrument een voordeel kan faken, kan de idiosyncratische structuur van het ene instrument ook een controle faken. De donorpool van SCM is het formele antwoord op precies dat bezwaar: in plaats van één vergelijkbaar actief te kiezen, laat u de gegevens van vóór de periode een gewogen mandje daarvan kiezen.
Difference-in-differences verdienen meer dan een zin, omdat het de bijna-ongeluk is. DiD vergelijkt de verandering in de behandelde eenheid met de verandering in een controlegroep, en identificeert het effect alleen onder parallelle trends: zonder de interventie zouden behandelde en controlegroep samen zijn gegaan. Op de financiële markten is deze veronderstelling vrijwel onverdedigbaar: activa verschillen qua bèta, qua volatiliteitsregime, qua liquiditeitsniveau, en hun relatieve pad dwaalt af. SCM vervangt de aanname door een passend object: in plaats van aan te nemen dat een besturingselement parallel beweegt, construeert het er een en laat je vervolgens zien hoe goed het feitelijk werd gevolgd. Als het slecht wordt gevolgd, wordt u verteld om te stoppen.
De methode

Opstelling en notatie
Overweeg eenheden (activa, strategieën of portefeuilles) waargenomen periodes. Eenheid 1 is de behandelde eenheid: het middel of de strategie waarbij u heeft ingegrepen. Eenheden vormen de donorpool van vergelijkbare onbehandelde eenheden.
Laten geven de uitkomst voor de behandelde eenheid op dat moment aan met de tussenkomst, en de uitkomst zonder. Het behandelingseffect op dat moment is:
Wij observeren direct. Het hele probleem is schatten .
Het construeren van de synthetische controle
SCM-schattingen als een gewogen gemiddelde van de donorresultaten:
waar de gewichtsvector voldoet voor iedereen En .
Deze twee beperkingen doen echt werk. Ze dwingen de synthetische controle om een convexe combinatie van donoren te zijn, wat extrapolatie buiten de ondersteuning van de gegevens voorkomt. Een onbeperkte regressie kan je een counterfactual opleveren die is opgebouwd uit een 3,4x longpositie in de ene munt tegen een 2,4x short in een andere – numeriek gezien een geweldige fit vóór de periode, en een counterfactual die overeenkomt met geen enkele portefeuille die iemand zou kunnen aanhouden. De convexiteitsbeperking maakt de contrafeitelijke interpretatie interpreteerbaar en de gewichten schaars: doorgaans krijgt slechts een handvol donoren een gewicht dat niet gelijk is aan nul, en u kunt ze lezen.
Optimale gewichtsselectie
Er worden gewichten gekozen om de afstand tussen de behandelde eenheid en de synthetische controle in de pre-interventieperiode te minimaliseren:
waar is een vector van pre-interventiekenmerken voor de behandelde eenheid, is de matrix met dezelfde kenmerken voor de donorpool, en is een positieve semi-definitieve diagonale matrix die belang toekent aan elke voorspeller.
wordt gekozen door middel van kruisvalidatie: pick zodanig dat het resultaat minimaliseert de gemiddelde kwadratische voorspellingsfout (MSPE) van de uitkomstvariabele in de pre-interventieperiode. Dit is een geneste optimalisatie: een buitenste lus , een innerlijke beperkte oplossing voor .
Voorspellingsvariabelen voor handelstoepassingen
Waar Abadie et al. gebruikte BBP per hoofd van de bevolking en de samenstelling van de industrie, handelstoepassingen willen:
- Rendementkenmerken: gemiddeld rendement, volatiliteit, scheefheid, kurtosis over de voorperiode
- Liquiditeitsmaatstaven: gemiddelde spread, dagelijks volume, Amihud-illiquiditeitsratio
- Microstructuurkenmerken: onbalans in de orderstroom, aankomstpercentage van transacties, verhouding tussen offerte en transactie
- Factorblootstelling: bèta-aan-markt-, momentum-, waarde- en volatiliteitsfactoren
- Vertraagde resultaten: cumulatieve PnL-waarden op verschillende data vóór de interventie
Vertraagde resultaten zijn het belangrijkst. Abadie et al. (2010) laten zien dat als de synthetische controle overeenkomt met de behandelde eenheid op het gebied van vertraagde uitkomsten gedurende een lange periode vóór de interventie, deze impliciet controleert op niet-geobserveerde confounders onder een lineair factormodel – wat de hele reden is dat de methode de moeite waard is. U hoeft de confounder die uw PnL veroorzaakte niet te noemen. U bent verplicht om donoren te vinden die er ook aan zijn blootgesteld.
Waar dit van toepassing is

Scenario 1: Evaluatie van een nieuw uitvoeringsalgoritme
U implementeert een nieuw TWAP-schema op één instrument en wilt het effect ervan op de implementatieachterstand. Zowel de statistiek als de algoritmefamilie worden elders uitgebreid besproken — zie implementation shortfall and TCA voor de kostendecompositie en TWAP/VWAP/POV-algoritmen voor de planners zelf. De SCM-bijdrage is de evaluatielaag erboven: de donorpool bestaat uit dezelfde instrumenten die nog steeds de oude planner draaien, over hetzelfde venster, zodat veranderingen in de spreiding of het volume binnen de hele locatie zowel op behandelde mensen als op donoren terechtkomen.
Pre-interventieperiode: 60 handelsdagen vóór de overstap. Post-interventieperiode: 30 handelsdagen erna. De effectschatting is de kloof:
Als de nieuwe planner daadwerkelijk de kosten verlaagt, hardnekkig na – en, nog belangrijker, het behandelde tekort bevindt zich buiten de wolk van donortekorten.
Scenario 2: Impact van een marktgebeurtenis
Een wijziging in het tariefschema, een tick-size pilot, een transactiebelasting of een wijziging van de regel voor stroomonderbrekers treft één locatie. Behandelde eenheid: uw strategie op de getroffen locatie. Donorpool: hetzelfde paar op locaties waar de verandering niet heeft plaatsgevonden. De effecten van de vergoedingsstructuur op de uitvoering worden afzonderlijk behandeld in maker-taker vergoedingen en kortingen; SCM zorgt ervoor dat "onze vullingen slechter zijn geworden na de verandering" in een schatting met een nul als bijlage.
Scenario 3: Wisselen van regime-voorwaardelijke strategie
Je schakelt over van mean-reversion naar momentum op één actief wanneer een regime-detection signal afgaat. Heeft de schakelaar het laten zitten? Donorpool: vergelijkbare activa waarbij het signaal werd afgegeven, maar u niet bent overgestapt. Let op de valkuil: als het signaal van het regime de hele markt afgaat, worden uw donoren ook behandeld en stort het ontwerp in. Zie de spillover-regel hieronder.
Placebotests en gevolgtrekkingen

De gevolgtrekking van SCM is gebaseerd op permutatie. Het algemene argument voor het bouwen van een empirische nul door resampling in plaats van te vertrouwen op een distributie in gesloten vorm wordt gegeven in Monte Carlo en bootstrap-methoden voor backtests; wat volgt is de SCM-specifieke constructie.
Placebo op tijd
Verschuif de interventiedatum terug naar de pre-periode – halverwege bijvoorbeeld – en voer de interventie opnieuw uit. Als SCM een ‘behandelingseffect’ constateert op een datum waarop er niets is gebeurd, pikt het reeds bestaande verschillen op, en niet uw tussenkomst. Een geloofwaardige synthetische controle vertoont geen effect op valse interventiedata.
Placebo in de ruimte (permutatietest)
Pas de gehele SCM-procedure toe op elke donor, waarbij u doet alsof elke donor op zijn beurt de behandelde eenheid was:
- Voor elke donor construeer een synthetische controle van de resterende donoren plus de oorspronkelijk behandelde eenheid.
- Bereken de post-interventiekloof .
- Vergelijk de kloof van de behandelde eenheid met de verdeling van de placeboverschillen.
De p-waarde is een rang:
waar
De verhouding is, in plaats van de ruwe kloof na de periode, de juiste statistiek: een donor die nooit goed fit is geweest, zal een grote kloof vertonen na de periode om redenen die niets met enige interventie te maken hebben, en delen door zijn MSPE vóór de periode bestraft precies dat.
Dit is dezelfde gevolgtrekking die de Deflated Sharpe Ratio maakt: rangschik uw kandidaat binnen een empirisch gegenereerde referentieverdeling, nooit tegen nul. DSR rangschikt uw winnaar tegen een best-of-N nul over proeven; SCM rangschikt uw behandelde eenheid tegen een nul boven eenheden. Er geldt een andere schatter, dezelfde discipline en dezelfde waarschuwing: met donoren de kleinst haalbare p-waarde is . Een permutatietest kan niet verder gaan dan zijn eigen granulariteit, dus een kleine donorpool beperkt de hoeveelheid betekenis die u mag claimen, hoe groot het effect ook lijkt.
Praktisch filteren
Abadie et al. adviseren om placebo-eenheden met een slechte pasvorm vóór de interventie uit te sluiten – meer dan vóór MSPE maal die van de behandelde eenheid, met doorgaans 2 tot 20. Slecht passende placebo's hebben kleine noemers en produceren enorme MSPE-ratio's, waardoor de referentieverdeling wordt verontreinigd en uw behandelde eenheid er onopvallend uitziet. Rapporteer de verhouding bij verschillende drempels; als uw p-waarde slechts op één bepaald punt significant is , je hebt een afstemmingsparameter gevonden, geen effect.
Implementatie

De onderstaande code gebruikt alleen numpy En scipy zodat de mechanismen zichtbaar zijn. Productiealternatieven — SparseSC (Microsoft-onderzoek), pysyncon, SyntheticControlMethods — omgaan met randgevallen en beter schalen.
Constructie van voorspellende matrix
import numpy as np
import pandas as pd
from scipy.optimize import minimize
def build_predictors(series: pd.Series, T0: int) -> np.ndarray:
"""
Extract predictor vector from pre-intervention data.
Features: mean return, volatility, skewness, kurtosis,
plus lagged outcome values at regular intervals.
"""
pre = series.iloc[:T0]
daily_ret = pre.diff().dropna()
stats = [
daily_ret.mean(),
daily_ret.std(),
daily_ret.skew(),
daily_ret.kurtosis(),
]
lag_indices = np.linspace(0, T0 - 1, 5, dtype=int)
lags = pre.iloc[lag_indices].values.tolist()
return np.array(stats + lags)
df hier is een panel van cumulatieve rendementen: behandelde eenheid in kolom 0, donoren in de rest, één rij per balk. Gebruik cumulatieve rendementen, geen prijsniveaus.
X1 = build_predictors(df["Treated"], T0).reshape(-1, 1) # (k x 1)
X0 = np.column_stack([ # (k x J)
build_predictors(df[col], T0) for col in df.columns[1:]
])
Gewichtsoptimalisatie
def solve_weights(
X1: np.ndarray,
X0: np.ndarray,
Y1_pre: np.ndarray,
Y0_pre: np.ndarray,
) -> np.ndarray:
"""
Solve for optimal synthetic control weights.
Nested optimization:
Outer: optimize V (predictor importance)
Inner: optimize w (donor weights) given V
"""
k = X1.shape[0]
J = X0.shape[1]
def solve_w_given_V(V_diag: np.ndarray) -> np.ndarray:
"""Inner: find w minimizing weighted predictor distance."""
V = np.diag(V_diag)
def objective(w):
gap = X1.flatten() - X0 @ w
return gap @ V @ gap
constraints = {"type": "eq", "fun": lambda w: np.sum(w) - 1.0}
bounds = [(0, 1)] * J
w0 = np.ones(J) / J
result = minimize(objective, w0, method="SLSQP",
bounds=bounds, constraints=constraints,
options={"maxiter": 1000, "ftol": 1e-12})
return result.x
def outer_objective(V_diag: np.ndarray) -> float:
"""Outer: minimize pre-period MSPE given V."""
w = solve_w_given_V(np.abs(V_diag))
return np.mean((Y1_pre - Y0_pre @ w) ** 2)
V0 = np.ones(k)
result = minimize(outer_objective, V0, method="Nelder-Mead",
options={"maxiter": 5000, "xatol": 1e-8})
return solve_w_given_V(np.abs(result.x))
Y1_pre = df["Treated"].iloc[:T0].values
Y0_pre = df.iloc[:T0, 1:].values
weights = solve_weights(X1, X0, Y1_pre, Y0_pre)
for col, w in zip(df.columns[1:], weights):
if w > 0.01:
print(f" {col}: {w:.4f}")
De gap-reeks is dan df["Treated"].values - df.iloc[:, 1:].values @ weights, uitgezet tegen de interventiedatum naast de donorhiaten uit de onderstaande placebo-run.
Placebotests
def run_placebo_tests(df: pd.DataFrame, T0: int) -> pd.DataFrame:
"""In-space placebo: treat each unit in turn as if intervened upon."""
results = []
all_columns = df.columns.tolist()
for placebo_col in all_columns:
donor_cols = [c for c in all_columns if c != placebo_col]
donor_df = df[donor_cols]
X1_p = build_predictors(df[placebo_col], T0).reshape(-1, 1)
X0_p = np.column_stack([
build_predictors(donor_df[c], T0) for c in donor_cols
])
w_p = solve_weights(
X1_p, X0_p,
df[placebo_col].iloc[:T0].values,
donor_df.iloc[:T0].values,
)
gap_p = df[placebo_col].values - donor_df.values @ w_p
mspe_pre = np.mean(gap_p[:T0] ** 2)
mspe_post = np.mean(gap_p[T0:] ** 2)
results.append({
"unit": placebo_col,
"mspe_pre": mspe_pre,
"mspe_post": mspe_post,
"mspe_ratio": mspe_post / mspe_pre if mspe_pre > 1e-10 else np.inf,
"gap_series": gap_p,
"is_treated": placebo_col == "Treated",
})
return pd.DataFrame(results)
placebo_results = run_placebo_tests(df, T0)
treated_pre = placebo_results.loc[placebo_results["is_treated"], "mspe_pre"].values[0]
filtered = placebo_results[placebo_results["mspe_pre"] <= 5 * treated_pre]
treated_ratio = filtered.loc[filtered["is_treated"], "mspe_ratio"].values[0]
p_value = (filtered["mspe_ratio"] >= treated_ratio).sum() / len(filtered)
print(f"MSPE ratio (treated): {treated_ratio:.2f} p = {p_value:.3f}")
De schatter kalibreren
Er is een demonstratie die de moeite waard is en een demonstratie die de moeite waard is om te weigeren. Het genereren van synthetische panelgegevens, het injecteren van een effect van +0,3%/dag, het herstel van ongeveer +0,3%/dag, en het presenteren daarvan als bewijs bewijst alleen dat SLSQP convergeert. Het is circulair en deze blog publiceert het niet.
Waar synthetische gegevens goed voor zijn, is kalibratie – dezelfde standaard die wordt toegepast in het DSR-stuk en PBO, waarbij de bekende nul de statistiek betrouwbaar maakt. Twee controles, beide uitgevoerd op gegevens die zijn gegenereerd op basis van een lineair factormodel met het aantal donoren en de lengte vóór de menstruatie die u daadwerkelijk heeft:
- Vermogen met een bekende effectgrootte. Injecteer een effect met een bekende omvang. Herstelt de geschatte kloof na de periode dit, en binnen welke fout? Verlaag de effectgrootte totdat het herstel mislukt. Die vloer is het kleinste effect dat uw paneelgeometrie kan detecteren, en elk echt resultaat daaronder is ruis, ongeacht de p-waarde ervan.
- Grootte onder een echte nul. Injecteer niets. Voer de volledige placebopijplijn uit. De p-waarde moet ongeveer uniform zijn , dus het zou ongeveer 10% van de tijd onder de 0,10 moeten vallen bij herhaalde trekkingen. Als het veel vaker gebeurt, is uw voorspellerset of filterdrempel van betekenis voor de productie en wordt de pijplijn verbroken voordat deze ooit echte gegevens raakt.
Controle 2 is degene die mensen overslaan en degene die er toe doet. Voer het eerst uit.
Praktische overwegingen

Kiezen van de donorpool
Donoren moeten plausibel vergelijkbaar zijn met de behandelde eenheid en niet beïnvloed door de interventie. Voor uitvoeringswerkzaamheden: hetzelfde algoritme op vergelijkbare instrumenten – dezelfde sector, marktkapitalisatiedeciel, liquiditeitslaag. De laagtaxonomie in multi-symbol validation is hier direct herbruikbaar; de eigenschappen die instrumenten tot een eerlijke robuustheidstest maken, maken ze ook tot een eerlijke donorpool. Voor locatie-evenementen: hetzelfde instrument op locaties waar de verandering niet werd bereikt.
Exclusief eenheden met overloop. Als het wijzigen van uw algoritme op één instrument uw quotering op gecorreleerde instrumenten heeft gewijzigd, worden die instrumenten gedeeltelijk behandeld. Als u ze binnen laat, wordt de synthetische controle vertekend in de richting van het post-periodepad van de behandelde eenheid en wordt uw schatting teruggebracht naar nul - een ontwerpfout die net zo gemakkelijk nulresultaten oplevert als een slechte controle positieve resultaten oplevert.
Pre-interventiefit is het hele argument
De geloofwaardigheid van SCM berust volledig op de fit vóór de periode. Rapporteer de MSPE vóór de interventie en toon de fit. Een slechte pre-fit maakt alles daarna ongeldig .
Abadie et al. (2015) stellen de regel duidelijk: als geen enkele convexe combinatie van donoren het pre-interventietraject van de behandelde eenheid reproduceert, pas de methode dan niet toe. Dit is een eerlijk vervalsingscriterium, en het is zeldzamer dan het zou moeten zijn; de meeste schatters retourneren een getal, ongeacht wat u ze geeft. SCM vertelt u wanneer het geen geloofwaardig contrafeitelijk resultaat kan opleveren, en het juiste antwoord op die boodschap is om de mislukking te publiceren, en niet om de donorpool uit te breiden totdat de fit verbetert. Het verbreden van de pool om pre-fit na te jagen is dezelfde overfitting waar de rest van deze serie over gaat, verplaatst naar de controle-constructiestap.
Overfitting in korte panelen
De SCM-specifieke hoeveelheid om in de gaten te houden is de verhouding van het aantal donoren naar observaties vóór de periode . Met vrije gewichten gemonteerd punten, een perfecte voorpassing wordt haalbaar door constructie als benadert – en een op die manier verkregen perfecte pre-fit bevat geen informatie. Houden aanzienlijk groter dan ; als een strategie 30 dagen vóór de wijziging liep en je hebt 20 kandidaat-donoren, heb je geen SCM-probleem, maar heb je een interpolatie. Maatregelen:
- Regularisatie: SparseSC voegt toe En boetes voor de gewichtsoptimalisatie.
- Beperk de donorpool: minder, beter gemotiveerde donoren verslaan meer donoren – ten koste van een grover permutatieraster, aangezien stelt ook uw minimale p-waarde in. Die spanning is reëel en heeft geen zuivere oplossing.
- Augmented SCM: Ben-Michael, Feller en Rothstein (2021) gebruiken een uitkomstmodel om bias te corrigeren wanneer een perfecte pre-fit onbereikbaar is.
Niet-stationariteit
Voer SCM uit op cumulatieve rendementen, nooit op prijsniveaus; niveaus nodigen uit tot valse veranderingen. Stel vast dat de kloof vóór de interventie een gemiddelde nulwaarde heeft en stationair is voordat u vertrouwt op de divergentie na de periode; de ADF- en Engle-Granger-machinerie daarvoor, inclusief de gecorrigeerde kritische waarden die je nodig hebt bij het testen van een gefit residu in plaats van een geobserveerde reeks, wordt behandeld in statistische arbitrage en parenhandel.
Meerdere behandelde eenheden
Door het in één keer op meerdere assets te implementeren, wordt het ontwerp met één behandelde eenheid doorbroken. Uitbreidingen: gepoolde SCM (gemiddelde effecten over behandelde eenheden) en gespreide adoptie ontwerpen (Ben-Michael et al., 2022) voor eenheden die op verschillende tijdstippen zijn behandeld.
Wanneer mag u SCM niet gebruiken?

Zeer geschikt voor: een discrete, goed gedefinieerde interventie op een bekende datum; een redelijke donorpool van vergelijkbare onbehandelde eenheden; interventies niet verwacht op voorhand, aangezien anticipatie de behandelde eenheid eerder verplaatst en in strijd is met de identificatie.
Slecht geschikt voor: continue behandeling, zoals een parameter die over weken verandert; instellingen zonder echt onbehandelde vergelijkingen; hoogfrequente evaluatie waarbij de signaal-ruisverhouding de gewichtsschatting verslaat.
Conclusie

Selectie en confounding zijn verschillende faalwijzen en vereisen verschillende instrumenten. DSR en PBO bepalen de zoektocht. SCM prijst het contrafeitelijke scenario, en het is het enige instrument in deze serie dat zich richt op het geval waarin u precies één experiment hebt uitgevoerd en het resultaat nog steeds niet kunt vertrouwen.
De reden om dit te verkiezen boven een ad-hocbenchmark is niet dat het grotere effecten oplevert – vaak kleinere – maar dat het kan weigeren. Als geen enkele convexe combinatie van donoren uw instrument vóór de interventie volgt, zegt SCM dat en stopt u. Als het behandelde gat zich in de donorwolk bevindt, zegt de placebo-p-waarde dat en rapporteert u een nul. Deze twee uitgangen zijn de waarde van de methode, en een SCM-beschrijving zonder een gerapporteerde MSPE van vóór de periode en een placebo-p-waarde heeft de enige delen overgeslagen die het meer maken dan een diagram van twee divergerende lijnen.
Verder lezen
- Abadie, A., Diamond, A., en Hainmueller, J. (2010). "Synthetische controlemethoden voor vergelijkende casestudies." Journal of the American Statistical Association, 105(490), 493-505.
- Abadie, A. (2021). "Gebruik van synthetische controles: haalbaarheid, gegevensvereisten en methodologische aspecten." Journal of Economic Literature, 59(2), 391-425.
- Ben-Michael, E., Feller, A., & Rothstein, J. (2021). "De verbeterde synthetische controlemethode." Journal of the American Statistical Association, 116(536), 1789-1803.
- Cunningham, S. (2021). Causale gevolgtrekking: de mixtape. Hoofdstuk 10: Synthetische controle. Verkrijgbaar op mixtape.scunning.com.
- Microsoft-onderzoek. SparseSC: schaarse synthetische controles. github.com/microsoft/SparseSC.
Auteurs
Trading-systems engineer
Trading-systems engineer building bots since 2017: cross-exchange arbitrage (connected up to 30 venues), cointegration-based pairs arbitrage across spot and futures, scalping, news and sentiment-driven strategies, trend algorithms, and portfolio management and balancing algorithms. Also builds sub-millisecond order execution, big-data warehouses, backtesting engines, AI agents, and trading interfaces (incl. open-source profitmaker.cc). Stack: JS/TS, Python, Rust/Zig/Go, DevOps, backend, frontend, architecture.