Lesson 7.5.1 · 45 min
Quant roles: six jobs around the same system
“Quant” is not a job, it is a family. The same strategy passes through whoever obtains and cleans the data, whoever finds the signal, whoever turns it into a system, whoever trades it, whoever watches its risk and whoever keeps the models running in production. This lesson describes the six roles, crosses them with the syllabus in a matrix you can run, and simulates how their working day is split up.
- Module
- 7.5 · Quant career
- Duration
- 45 min
- Prerequisites
- 2.2.4 · Research journal and experiment tracking against data snooping, 4.5.1 · Live system architecture: from data to reconciliation
- Author
- Jesús Cuesta
- Updated
Level 7 lessons
7.1 · Software engineering for trading
7.2 · Infrastructure and deployment
7.3 · MLOps for trading models
7.4 · Regulation, ethics and taxation
- 7.4.1 MiFID II: clients, suitability and algorithmic trading
- 7.4.2 ESMA and CFDs: leverage, close-out and negative balance
- 7.4.3 PRIIPs, the KID and US ETFs
- 7.4.4 MiCA after the transitional period: checking a provider in the registers
- 7.4.5 Market abuse: spoofing, layering and the bot that imitates them by accident
- 7.4.6 Trading taxes in Spain
- 7.4.7 Ethics: personal data, artificial intelligence and selling signals
7.5 · Quant career
7.6 · Final capstone
- 7.6.1 Capstone: common requirements, the panel's rubric and preparing the defense
- 7.6.2 Capstone C1: a multi-asset futures system, from forecast to paper account
- 7.6.3 Capstone C2: systematic options book, volatility surface and real-time Greeks
- 7.6.4 Capstone C3: stock and ETF portfolio with ML, HRP and Spanish taxation
- 7.6.5 Capstone C4: a research platform with LLMs and alternative data
- 7.6.6 Capstone C5: crypto market making or arbitrage with counterparty control
One system, six jobs
A systematic trading system is a chain: data coming in, a signal being researched, a program that executes it, a person who operates it, some limits that contain it and, if there are machine learning models, a cycle that retrains and monitors them. In a large firm, each link has its own team; in a small one, or for an independent trader, a single person does several. Knowing which link you are working on at each moment helps decide what to learn, what to delegate and which positions to apply for.
Mermaid source
flowchart TB DE[Data engineer] --> QR[Quant researcher] QR --> QD[Quant developer] ML[ML engineer] --> QD QD --> QT[Quant trader] RQ[Risk quant] --> QT QT --> QR
The return arrow, from the trader to the researcher, is the one most often forgotten: what is observed live (costs, fills, drift) goes back into research. The names are the usual ones in the industry, but they are not standardized: the same job can be called quantitative analyst, strategist, research engineer or portfolio analyst depending on the firm. That is why this lesson defines each role by its deliverables and not by its title.
A public reference for the tasks is O*NET, the occupational database of the U.S. Department of Labor. Its Financial Quantitative Analysts profile (13-2099.01) lists 21 tasks, among them “Apply mathematical or statistical techniques to address practical issues in finance, such as derivative valuation, securities trading, risk management, or financial market regulation”, “Develop core analytical capabilities or model libraries” and “Provide application or analytical support to researchers or traders”; among the sample of reported job titles the profile lists Quantitative Analyst, Quantitative Research Analyst and Portfolio Manager. The Financial Risk Specialists profile (13-2054.00) includes “Devise scenario analyses reflecting possible severe market events” and “Contribute to development of risk management systems”1Note 1 · O*NET OnLine, U.S. Department of Labor, Employment and Training Administration: profiles 13-2099.01 Financial Quantitative Analysts, 13-2054.00 Financial Risk Specialists and 15-2051.00 Data Scientists (site updated on October 6, 2026), accessed on October 23, 2026. CC BY 4.0 license; the quotations are the original English wording (checked again on November 5, 2026).. They are descriptions of the U.S. labor market, useful as vocabulary; they are not a European standard nor a guarantee of what each job posting asks for.
What each role does
| Role | Deliverable | Typical tools | Course modules |
|---|---|---|---|
| Quant researcher | Tested hypothesis, report and reproducible prototype | pandas, Polars, statsmodels, scikit-learn, notebooks, experiment tracking | 0.7, 2.1–2.6, 4.1, 5 |
| Quant developer | System in production: live data, orders, state, tests | Typed Python, pytest, asyncio, broker APIs, NautilusTrader or LEAN, Docker | 2.4, 4.4, 4.5, 7.1, 7.2 |
| Quant trader | Daily trading, execution and decisions within limits | Broker platform, monitors, execution reports, Greeks | 1.1, 3, 4.2, 4.3 |
| Data engineer | Clean, versioned and timely data | Parquet, DuckDB, orchestrators, queues, schema validation | 1.3, 1.4, 6.6, 7.2 |
| Risk quant | Measures, limits, stress scenarios and controls | VaR and ES, stress testing, derivatives valuation, reports | 3.4, 4.2, 7.4 |
| ML engineer | Models that are served, monitored and retrainable | scikit-learn, PyTorch, MLflow, ONNX, drift monitoring | 5, 6, 7.3 |
- Quant researcher. Formulates edge hypotheses (lesson 2.2.1), tests them with data and honest statistics, and discards most of them. Their professional risk is overfitting, and their tools to fight it are those of module 2.5. A good researcher leaves a trail that someone else can reproduce: journal, versioned data and code (2.2.4).
- Quant developer. Turns the prototype into a system that does not crash, or that crashes in a controlled way: order states, reconnections, idempotency and reconciliation (4.5), project structure, tests and performance (7.1), deployment (7.2). Their risk is the silent error: the duplicated order or the stale data point that nobody sees.
- Quant trader. Operates the system and decides within limits: when to pause, how to execute large orders (4.3), what to do about an event the model does not know. In options or futures strategies they manage Greeks and rolls (modules 3.1 and 3.5). They are the first to see that something does not add up.
- Data engineer. Builds and maintains the data flows: downloads with retries, cleaning, corporate action adjustments, universes without survivorship bias and efficient storage (1.4), at scale when needed (6.6). Their work is invisible when it works.
- Risk quant. Measures and limits: VaR and Expected Shortfall with their backtesting, correlation and liquidity stress, derivatives risk (4.2), independent valuation (3.4). In a regulated firm they translate regulatory requirements into controls (7.4).
- ML engineer. Takes models to production and keeps them healthy: experiment and model tracking, retraining with validation, champion/challenger, drift monitoring and efficient serving (7.3), on top of the financial validation foundation of level 5.
The skills matrix
The table above can be turned into data. The following matrix assigns each block of the syllabus a weight per role: 0 if it is unrelated to the job, 1 if it is useful, 2 if it is important and 3 if it is core. It is the course's assessment, not a survey: it is written so that it can be debated and changed, and the code that uses it does not depend on the specific numbers.
import pandas as pd
ROLES = ["researcher", "developer", "trader", "data_eng",
"risk", "ml_eng"]
# 0 = unrelated, 1 = useful, 2 = important, 3 = core to the job
MATRIZ = pd.DataFrame.from_records([
# skill, course modules, weights per role (order of ROLES)
("Statistics and econometrics", "0.7 2.1", 3, 1, 2, 1, 3, 2),
("Backtesting and validation", "2.4 2.5", 3, 2, 2, 0, 2, 2),
("Derivatives and valuation", "3.4 3.5", 2, 1, 3, 0, 3, 0),
("Portfolios and risk", "4.1 4.2", 2, 1, 3, 0, 3, 1),
("Microstructure and execution", "1.1 4.3", 1, 2, 3, 1, 1, 0),
("Data and pipelines", "1.4 6.6", 2, 2, 1, 3, 1, 2),
("Live systems", "4.4 4.5", 0, 3, 2, 1, 1, 1),
("Machine learning", "5.1 5.4", 2, 1, 1, 1, 1, 3),
("LLMs and alternative data", "6.2 6.7", 1, 1, 0, 2, 0, 2),
("Software engineering", "7.1 7.2", 1, 3, 1, 3, 1, 3),
("MLOps", "7.3", 0, 2, 0, 2, 0, 3),
("Regulation and ethics", "7.4", 1, 1, 2, 1, 3, 1),
], columns=["competencia", "modulos", *ROLES]).set_index("competencia")
print(MATRIZ[ROLES].sum().rename("sum of weights").to_string())researcher 18
developer 20
trader 20
data_eng 15
risk 19
ml_eng 20The header figure draws the same matrix: each square is a weight, and its size, the value. The sum of weights indicates the breadth of each role. The data engineer is the most concentrated (15); the developer, the trader and the ML engineer, the broadest (20). The core skills of each one:
for rol in ROLES:
print(rol)
for competencia in MATRIZ.index[MATRIZ[rol] == 3]:
print(" -", competencia)researcher
- Statistics and econometrics
- Backtesting and validation
developer
- Live systems
- Software engineering
trader
- Derivatives and valuation
- Portfolios and risk
- Microstructure and execution
data_eng
- Data and pipelines
- Software engineering
risk
- Statistics and econometrics
- Derivatives and valuation
- Portfolios and risk
- Regulation and ethics
ml_eng
- Machine learning
- Software engineering
- MLOpsTwo readings of the matrix. Software engineering is core for three roles (developer, data engineer and ML engineer) and is unrelated to none: code is everyone's working medium. And regulation is core only for the risk quant, the amber cell in the figure, although nobody can ignore it: a badly designed bot can amount to market manipulation (lesson 7.4.5), and that affects both whoever programs it and whoever operates it.
Self-assessment and gap
With the matrix, a self-assessment on the same scale (0 to 3) becomes a coverage per role: the share of what the role requires that you already have, weighted by each skill's weight. Knowing more than is required does not make up for what is missing in another skill, so the excess is clipped.
# Example self-assessment, from 0 (nothing) to 3 (I master it)
YO = pd.Series({
"Statistics and econometrics": 2, "Backtesting and validation": 3,
"Derivatives and valuation": 1, "Portfolios and risk": 2,
"Microstructure and execution": 1, "Data and pipelines": 2,
"Live systems": 1, "Machine learning": 2,
"LLMs and alternative data": 1, "Software engineering": 2,
"MLOps": 0, "Regulation and ethics": 1,
})
def cobertura(yo, matriz=MATRIZ, roles=ROLES):
"""Covered share of what each role requires, by weight."""
pide = matriz[roles]
tengo = pide.clip(upper=yo, axis=0) # the excess does not count
return (tengo.sum() / pide.sum()).sort_values(ascending=False)
print(cobertura(YO).map("{:.0%}".format).to_string())researcher 89%
developer 70%
ml_eng 70%
risk 68%
data_eng 67%
trader 65%The example profile, someone who has done level 2 well and the others halfway, covers 89% of what the researcher role requires and between 65% and 70% of the rest. Coverage is not a grade: with the 0 to 3 scale and twelve skills it is a coarse measure, good for ordering priorities and bad for comparing people. For the developer role, the specific list:
def brecha(rol, yo, matriz=MATRIZ):
falta = (matriz[rol] - yo).clip(lower=0)
tabla = matriz.loc[falta > 0, ["modulos"]].assign(
pide=matriz[rol], tengo=yo, falta=falta)
return tabla.sort_values(["falta", "pide"], ascending=False)
brecha("developer", YO) modulos pide tengo falta
competencia
Live systems 4.4 4.5 3 1 2
MLOps 7.3 2 0 2
Software engineering 7.1 7.2 3 2 1
Microstructure and execution 1.1 4.3 2 1 1The gap reads as a plan (the columns are pide, what the role requires; tengo, what you have; and falta, what is
missing): live systems (modules 4.4 and 4.5) and MLOps (7.3) first, because two points are missing in each; then
software engineering (7.1 and 7.2) and microstructure (1.1 and 4.3). With the weights and the self-assessment in code,
the plan is recalculated every time they change, which is the advantage over a mental list.
A working day, as a model
Job descriptions say what is done, not how the day is split up. Two simple models help think about it. The first
describes a quant trader's session as a state machine, just like the system they operate (lesson 4.5.1): each event is
only valid in certain states. The states and events keep the identifiers of the code: preapertura (pre-open),
sesion (session), incidencia (incident), cierre (close) and revision (review); datos_ok and datos_mal are
good and bad data, alerta and resuelta an alert and its resolution, fin_mercado the market close, conciliado
the reconciliation and informe the report.
Mermaid source
stateDiagram-v2 [*] --> preapertura preapertura --> sesion: datos_ok preapertura --> incidencia: datos_mal sesion --> incidencia: alerta incidencia --> sesion: resuelta incidencia --> cierre: kill_switch sesion --> cierre: fin_mercado cierre --> revision: conciliado revision --> [*]: informe
A fictitious log of one day, with two resolved alerts, walked through the machine:
from datetime import datetime
TRANSICIONES = {
("preapertura", "datos_ok"): "sesion",
("preapertura", "datos_mal"): "incidencia",
("sesion", "alerta"): "incidencia",
("incidencia", "resuelta"): "sesion",
("incidencia", "kill_switch"): "cierre",
("sesion", "fin_mercado"): "cierre",
("cierre", "conciliado"): "revision",
("revision", "informe"): "fuera",
}
# Log of a fictitious day of a quant trader (Madrid time)
BITACORA = [
("08:00", "inicio"), ("08:40", "datos_ok"), ("11:20", "alerta"),
("11:55", "resuelta"), ("15:40", "alerta"), ("15:55", "resuelta"),
("17:35", "fin_mercado"), ("18:05", "conciliado"),
("18:30", "informe"),
]
def recorrer(bitacora, transiciones=TRANSICIONES):
"""Minutes in each state; an impossible event is an error."""
hora = lambda h: datetime.strptime(h, "%H:%M")
estado, desde = "preapertura", hora(bitacora[0][0])
minutos = {}
for h, evento in bitacora[1:]:
nuevo = transiciones.get((estado, evento))
if nuevo is None:
raise ValueError(f"{h}: “{evento}” is not valid in {estado}")
dur = (hora(h) - desde).seconds // 60
minutos[estado] = minutos.get(estado, 0) + dur
estado, desde = nuevo, hora(h)
return estado, minutos
final, minutos = recorrer(BITACORA)
print("Final state:", final)
for estado, m in minutos.items():
print(f" {estado:<12}{m:>4} min")Final state: fuera
preapertura 40 min
sesion 485 min
incidencia 50 min
cierre 30 min
revision 25 minOut of 10 and a half hours, 50 minutes were incidents and 95 minutes went into pre-open, close and review: tasks that do not appear in a backtest and that someone has to do every day. The machine rejects an impossible log (an alert “resolved” without being in an incident), which also makes it useful for auditing real logs.
The second model measures focus time. Each role receives interruptions (an alert, a question, a data failure) at a different rate and with a different average duration. The parameters are assumptions, not data: the trader receives many short interruptions; the data engineer, few and long ones; the researcher, few. With 250 simulated days per role, the model counts how many uninterrupted 90-minute blocks remain between 9:00 and 18:00:
import numpy as np
# Model assumptions (not data): interruptions per hour and
# average duration in minutes, per role
INTERRUPCIONES = {"researcher": (0.3, 15), "developer": (0.6, 25),
"trader": (1.5, 10), "data_eng": (0.5, 30),
"risk": (0.7, 20), "ml_eng": (0.5, 20)}
def simular_dia(tasa, media, rng, inicio=9 * 60, fin=18 * 60):
"""Minutes of interruption and focus blocks of >= 90 minutes."""
t, bloques, perdido = inicio, 0, 0
while True:
siguiente = t + rng.exponential(60 / tasa)
foco = min(siguiente, fin) - t
bloques += int(foco // 90)
if siguiente >= fin:
return perdido, bloques
dura = min(rng.exponential(media), fin - siguiente)
perdido += dura
t = siguiente + dura
rng = np.random.default_rng(7)
filas = []
for rol, (tasa, media) in INTERRUPCIONES.items():
dias = [simular_dia(tasa, media, rng) for _ in range(250)]
perdido, bloques = np.array(dias).T
filas.append((rol, perdido.mean() / 60, bloques.mean(),
(bloques == 0).mean()))
dia = pd.DataFrame(filas, columns=["rol", "horas_interrumpidas",
"bloques_90", "dias_sin_bloque"])
dia.set_index("rol").round(2) horas_interrumpidas bloques_90 dias_sin_bloque
rol
researcher 0.60 4.06 0.00
developer 1.85 2.64 0.03
trader 1.74 1.12 0.28
data_eng 1.72 3.06 0.02
risk 1.66 2.50 0.03
ml_eng 1.33 3.04 0.00The columns are interrupted hours per day, 90-minute blocks and the share of days without a block. The developer and the trader lose a similar amount of time (1.85 and 1.74 hours a day), but the trader keeps 1.12 focus blocks on average and has none on 28% of days; the developer, 2.64. The difference lies in the frequency: many short interruptions chop up the day. The practical consequence is organizational, not a matter of character: a trader's deep research fits outside the session, and an on-call developer needs rotating on-call shifts so that the rest of the team keeps their blocks.
How to use the rest of the level
The capstone projects of level 7 can be read with the same matrix. C1 (multi-asset futures system in NautilusTrader) is mostly developer and trader work; C2 (options book with real-time Greeks), trader and risk quant; C3 (portfolio with ML, HRP and taxes), researcher and ML engineer; C4 (platform with LLMs and alternative data), data engineer and ML engineer; C5 (market making or crypto arbitrage), developer and trader. Choosing the capstone according to the role you aspire to turns the project into a test of that role, which is what an interview asks about (lesson 7.5.3).
Two warnings. The first: in small teams the roles merge, and a profile with high coverage in two adjacent roles (researcher and developer, or data engineer and ML engineer) is more useful than a perfect one in a single role. The second: the matrix describes skills, not worth; everyone fills in the 0 to 3 scale about themselves, with the biases of any self-assessment. Checking it against published work (a repository, a reproducible report) is the subject of lesson 7.5.3.
Exercises
- Add to the matrix an execution quant role, who designs execution algorithms and measures costs, with the weights you find reasonable, and compute its coverage with the example self-assessment.
Solution
ejec = pd.Series({
"Statistics and econometrics": 2, "Backtesting and validation": 1,
"Derivatives and valuation": 0, "Portfolios and risk": 1,
"Microstructure and execution": 3, "Data and pipelines": 2,
"Live systems": 3, "Machine learning": 1,
"LLMs and alternative data": 0, "Software engineering": 2,
"MLOps": 1, "Regulation and ethics": 2,
})
m7 = MATRIZ.assign(execution=ejec)
print(cobertura(YO, m7, ROLES + ["execution"])
.map("{:.0%}".format).to_string())researcher 89%
developer 70%
ml_eng 70%
risk 68%
data_eng 67%
execution 67%
trader 65%With these weights, the execution role is among those with the lowest coverage for the example profile, because it concentrates its weight on microstructure and live systems, exactly where the self-assessment is lowest. The weights are an opinion: what is useful is that, when they change, the conclusion is recalculated and can be debated with numbers.
- A team sets up rotating on-call shifts: the on-call developer receives twice the interruptions and the other developers, one in four (0.15 per hour). How many focus blocks do those who are not on call gain?
Solution
rng = np.random.default_rng(11)
for nombre, tasa in [("on call", 1.2), ("off call", 0.15),
("no rotation", 0.6)]:
dias = np.array([simular_dia(tasa, 25, rng) for _ in range(250)])
print(f"{nombre:<13}{dias[:, 1].mean():>5.2f} 90-min blocks")on call 1.25 90-min blocks
off call 4.85 90-min blocks
no rotation 2.63 90-min blocksThose who are not on call go from 2.63 daily blocks to 4.85; the one on call drops to 1.25. With four developers and one on-call shift per week, each one has three weeks out of four with almost double the focus time. The model is crude (independent interruptions, exponential duration), but the order of magnitude explains why production teams separate on-call duty and development.
- Choose the role you aspire to and write, for the capstone you would choose, three deliverables that demonstrate the core skills of that role according to the matrix.
Solution
An example for the risk quant role with capstone C2: a VaR and Expected Shortfall report of the options book with its backtesting (Kupiec and Christoffersen, lesson 4.2.3); a set of stress scenarios with volatility and correlation jumps applied to the Greeks (4.2.4 and 4.2.6); and a table of limits (delta, vega, daily loss) with the control that applies them before each order and its log of breaches. The three cover the core skills of the role (statistics, derivatives, portfolios and risk, regulation) and can be shown in an interview.
Footnotes
-
O*NET OnLine, U.S. Department of Labor, Employment and Training Administration: profiles 13-2099.01 Financial Quantitative Analysts, 13-2054.00 Financial Risk Specialists and 15-2051.00 Data Scientists (site updated on October 6, 2026), accessed on October 23, 2026. CC BY 4.0 license; the quotations are the original English wording (checked again on November 5, 2026). ↩
Each answer is folded under its question
Self-assessment
A mean reversion model works in the backtest, but it has to be taken to a system that receives live data, sends orders to the broker and recovers from a disconnection. Which role is naturally responsible for that step?
- AThe quant researcher, because the model is theirs
- BThe risk quant
- CThe quant developer: turning research into reliable production software is the core of the job
- DThe data engineer
Show answer
Answer C. The quant developer: turning research into reliable production software is the core of the job
The researcher delivers a specification and a prototype; the developer builds the system with order states, reconnections, idempotency and tests (modules 4.4, 4.5 and 7.1). In small teams they can be the same person, but they are two different jobs.
In the lesson's matrix, for which role is regulation a core skill?
- AFor the risk quant
- BFor the quant researcher
- CFor the ML engineer
- DFor none
Show answer
Answer A. For the risk quant
It is the amber cell in the header figure. The risk quant translates regulatory and internal limits into measures and controls; the other roles need to know them (weight 1 or 2), but they are not their deliverable. The matrix is the course's assessment, not an industry survey.
With the example self-assessment, the role with the highest coverage is researcher (89%) and developer stays at 70%. What does the
brecha(gap) function say should be reviewed first for the developer role?- AStatistics and econometrics
- BDerivatives and valuation
- CMachine learning
- DLive systems (4.4 and 4.5) and MLOps (7.3), two points short each
Show answer
Answer D. Live systems (4.4 and 4.5) and MLOps (7.3), two points short each
brechasorts by what is missing and, on a tie, by the weight the role requires. Live systems is core for the developer (3) and the self-assessment gives 1; MLOps requires 2 and gives 0.In the interruption simulation, the trader has on average 1.12 focus blocks of 90 minutes a day and the researcher more than 4, with roughly the same interrupted hours as the developer. Which conclusion is correct?
- AThe trader works less
- BWhat destroys focus is the frequency of interruptions, not only their total duration: many short interruptions split the day into pieces useless for deep work
- CThe simulation proves that trading does not require concentration
- DThe numbers are industry data
Show answer
Answer B. What destroys focus is the frequency of interruptions, not only their total duration: many short interruptions split the day into pieces useless for deep work
Trader and developer lose a similar amount of time (about 1.7 to 1.9 hours), but the trader receives 1.5 interruptions per hour against 0.6. The parameters are model assumptions, not data: the lesson is the mechanism, which anyone can recalibrate with their own working day.
Key points
- The six roles work on the same system at different links of the chain: data (data engineer), signal (researcher), software (developer), trading (trader), limits (risk quant) and models in production (ML engineer).
- Titles change from one firm to another; what is stable is the deliverables. O*NET, from the U.S. Department of Labor, describes the quant analyst by tasks such as applying statistical techniques to valuation, trading or risk and maintaining model libraries.
- The lesson's skills matrix is an explicit assessment by the course that can be debated and changed; its value lies in making roles comparable and measuring gaps with code.
- With the example self-assessment, coverage goes from 89% (researcher) to 65% (trader), and the developer's gap points to live systems and MLOps.
- Each role's working day can be modeled: as a state machine (the trader's session) or as an interruption process. With the lesson's assumptions, the trader keeps 1.1 focus blocks of 90 minutes a day and the researcher, 4.1.