A Data Scientist at QUANTCO operates at the intersection of advanced quantitative science, software engineering, and strategic business consulting. Unlike traditional data science roles that focus solely on building isolated models, QUANTCO tasks its data science team with developing robust, scalable algorithms that solve high-stakes business problems. These problems range from dynamic pricing engines for multi-billion dollar retail giants to predictive models that optimize risk management for global insurance providers.
The impact of this role is immediate and visible. You will not just clean data or run off-the-shelf packages; you will design custom mathematical frameworks, test rigorous statistical assumptions, and translate complex algorithmic outcomes into actionable client strategies. QUANTCO prides itself on mathematical precision and software engineering excellence, meaning your models must be both theoretically sound and production-ready.
This position is highly collaborative and intellectually demanding. You will work closely with clients, software engineers, and product specialists to turn highly ambiguous, messy data into elegant, scalable solutions. For candidates who thrive on deep mathematical inquiry, clean coding practices, and direct business impact, the role offers an unparalleled environment to grow and excel.
Initial Screening
reportedWhoever runs this call is usually not a practitioner. They take notes, and a hiring manager skims those notes later, so the real question is whether your work survives being written down by someone outside the field. Test every project sentence against that: could a non-specialist repeat it correctly without knowing what a propensity score is? Carry a plain-language version of each project and one reason you want this particular role that you could not copy onto another application. Vagueness at this stage reads as inexperience, even when the underlying work was genuinely deep.
What to demonstrate
- Whether a non-specialist can restate your projects accurately, since their paraphrase is what reaches the hiring manager
- Whether your reason for wanting the role points at the work itself rather than the company's reputation
- Whether your language signals the level being screened for: what you decided yourself versus what you were handed
How to prepare
- Write a two-sentence, jargon-free version of each major project: the question nobody could answer, and the decision your work changed. Read it to someone outside data and have them repeat it back
- Point your 'why this role' answer at something concrete in the job description or the product surface you would be working on, and keep it to two sentences
- Have two questions ready about measurement: which metric the team is held to, and who acts on an analysis once it lands
Theoretical Math Rounds
reportedBecause the format is not fixed, prepare the reasoning rather than the ritual. Nearly every version of this round draws on the same underlying material: a design you can defend, a metric you can define exactly, an analysis whose assumptions you can state out loud. Only the wrapper changes, whether that is a take-home, a live case, a deep dive on past work, or a rough estimate on a whiteboard. Answers rehearsed to fit one shape stall the moment the shape differs. Practise naming the assumption behind a number, then saying how much the conclusion moves if that assumption is wrong.
What to demonstrate
- Whether your justification for a method survives the question 'why not the simpler thing', including when the simpler thing would have worked
- Precision under pressure: what exactly counts as an active user, a conversion or a success, over what window, with what exclusions
- Whether you carry an argument through to a recommendation instead of stopping at a list of tradeoffs
How to prepare
- For each project you plan to mention, write the metric definition in one sentence: numerator, denominator, time window, exclusions. Say it out loud once, because vagueness shows up in speech before it shows up on paper.
- Rehearse the same project at three lengths: two minutes, ten minutes, and a deep dive on one technical decision. Cutting live is harder than it sounds.
- For your headline result, write down what would have had to be true for it to be wrong, and how you ruled that out.
Hands-on Coding Challenge
reportedMuch of what gets scored here happens out loud while you type. Nobody can see your reasoning inside a half-written query, so five silent minutes read as being stuck even when they are not. State the plan in plain language first: which tables, what grain you are aggregating to, and the one filter that defines the population. Then write it. The narration doubles as insurance, because a wrong plan gets caught early and cheaply while a wrong query gets caught at the end with no time left to redo it. A timed statistics section, where one exists, is a separate test with its own clock.
What to demonstrate
- Whether the query you write matches the plan you just described
- What you do with a hint, meaning whether the correction gets absorbed or the first approach gets defended
- Whether you can debug your own wrong output by reading the result set and naming which part of the query produced the anomaly
How to prepare
- Solve three problems while screen-sharing into a recording, then watch it back and mark every stretch longer than thirty seconds where you said nothing
- Practise compressing the plan into one sentence before typing, then check afterwards whether the finished query actually matched it
- Time yourself on statistics questions that carry a business reading, such as what a confidence interval does and does not claim, rather than re-reading notes without a clock
Final Partner Interviews
reportedA day of back-to-back interviews samples your floor, not your ceiling. Four hours in, the habits that carry a good answer are the first to go: restating the question before solving it, asking what the data would have to look like, checking a number before quoting it. What the day decides is whether the tired version of you is still someone to leave alone with an ambiguous problem. The round that sinks a candidate is usually not the hardest one. It is the one immediately after the round that went badly.
What to demonstrate
- Whether the late rounds get the same clarifying questions as the first one, or whether you start answering immediately to save effort
- Whether a weak answer stays in the room it happened in, instead of following you into the next conversation as apology or distraction
- Whether the quality of your questions holds up, since fatigue removes curiosity about the problem before it removes knowledge of the method
How to prepare
- Rehearse the length, not just the content: book four mock interviews of different types in one afternoon with short gaps, because the one you need to observe is the fourth
- Put the two or three questions you ask at the start of any problem on a card in front of you, so that under fatigue it is a habit you run rather than a decision you make
- Decide in advance what the gap between rooms is for: water, one line of notes on anything you promised to follow up, and an explicit close on the round that just ended so it does not travel
- Prepare a different closing question for each interviewer, so the end of a long day does not produce the same one four times
PracHub editorial advice for the preparation topics above.
Joining research panels to the current instrument master instead of its effective-dated version, so delisted, merged and bankrupt names silently disappear from the historical universe.
The names that leave a universe leave disproportionately after bad returns, so removing them raises backtested return and lowers backtested volatility at the same time. The bias is largest exactly where the strategy claims to add value, in the tails, and it is invisible in the output: the query succeeds, the row count looks plausible, and the equity curve simply looks better than it should. The fix is to resolve universe membership with a predicate on effective_from and effective_to, never on status = 'active'.
Computing a t-statistic on daily observations of an h-day forward return as if the observations were independent.
Sampling an h-day forward return every day means consecutive observations share h-1 days of the same return, which induces strong positive autocorrelation. The naive standard error is too small by a factor on the order of sqrt(h), so a 5-day-horizon signal with a genuine t of 1.3 can present as 2.9. Either use non-overlapping samples, which costs power, or use a Newey-West or Hansen-Hodrick covariance with at least h-1 lags, and state which one was used.
Writing SQL without stating NULL and tie-breaking behaviour
Before calling a query finished, say what it does with NULLs, ties and empty groups. NOT IN against a subquery containing a single NULL returns no rows at all, and RANK, DENSE_RANK and ROW_NUMBER differ precisely on ties, so name which one the question requires.
Defining the cohort on a post-treatment condition
Ask how rows entered the table. Filtering on something that treatment itself influences, such as users who finished onboarding or accounts still active at ninety days, breaks comparability between arms; define the population at an entry point that precedes exposure and keep everyone in it.
Choose a category, try a prompt, then open its approach, worked solution or follow-up when you need it.
How do you calculate the expected value of a continuous random variabl…
How do you calculate the expected value of a continuous random variable? Walk through the mathematical steps.
Approach
- Write down the assumption the method needs before you use the method.
- Sanity-check the answer against a simple bound or a simulated case.
- Quantify uncertainty explicitly rather than reporting a point estimate alone.
Follow-up
- Which assumption here is most likely to be violated in practice?
- What sample size would you need to detect an effect half this size?
Solve a classic conditional probability puzzle involving Bayes' Theore…
Solve a classic conditional probability puzzle involving Bayes' Theorem (e.g., diagnostic test accuracy or Monty Hall variation).
Approach
- Translate the result into the decision it informs, in one plain sentence.
- Sanity-check the answer against a simple bound or a simulated case.
- Write down the assumption the method needs before you use the method.
Follow-up
- How would you explain this result to someone who does not know statistics?
- What sample size would you need to detect an effect half this size?
How would you design an experiment to test the effectiveness of a new …
How would you design an experiment to test the effectiveness of a new algorithmic pricing model against an existing baseline?
Approach
- Pick an evaluation metric that matches the cost of each error type, not a default.
- Frame the prediction: the label, the moment of prediction, and the action it triggers.
- Say how the offline result would be validated online before it is trusted.
Follow-up
- Where could label leakage enter this setup?
- How would you choose the decision threshold, and who owns that choice?
Describe the bias-variance tradeoff. How does increasing model complex…
Describe the bias-variance tradeoff. How does increasing model complexity impact training error versus test error?
Approach
- Say how the offline result would be validated online before it is trusted.
- Set a baseline first, so any model has something honest to beat.
- Check what information would not exist at prediction time, and exclude it.
Follow-up
- Where could label leakage enter this setup?
- How would you choose the decision threshold, and who owns that choice?
Build a point-in-time as-of join without merge_asof
Two frames. sig: instrument_id (int64), knowledge_ts (tz-aware UTC, irregular, several rows per instrument per day), zscore_xs, about 7.5M rows across 5,000 instruments. bars: instrument_id, bar_close_ts (tz-aware UTC, one row per instrument per trading day), fwd_ret_5d, about 7.5M rows. For each bar row attach the most recent zscore_xs whose knowledge_ts is at or before that instrument's bar_close_ts, or NaN when the newest such score is more than 10 calendar days old. You may not use pd.merge_asof.
Approach
- Concatenate both frames with a source flag, sort by (instrument_id, ts, is_bar) so signal rows precede bar rows at an identical timestamp, then groupby('instrument_id')[[...]].ffill() and keep the bar rows. One sort and one forward fill, with no per-group Python.
- Carry the signal's knowledge_ts through the forward fill as its own column. It is the only way to apply the 10-day staleness cap afterwards, and it is the audit trail showing which score each bar actually used.
- The alternative is two searchsorteds. Factorize instrument_id to dense codes, compress both timestamp arrays to a shared integer rank, form key = code*(n_unique_ts+1) + rank so lexicographic order becomes numeric order, then np.searchsorted(sig_key, bar_key, side='right') - 1. Validate that the found row belongs to the same instrument, or the last row of one instrument is silently attached to the first bar of the next.
- Normalize timezones before sorting. A tz-naive column compared against a tz-aware one raises in current pandas and compared wrongly in older ones; convert both with dt.tz_convert('UTC') and assert the dtype rather than trusting the loader.
- Apply the cap as (bar_close_ts - carried_knowledge_ts) > Timedelta('10D') and set those to NaN. Report the NaN share by month: a rising share is usually a vendor outage or a delisted name still present in the bar file.
Worked solution 30 min
- Rename sig.knowledge_ts and bars.bar_close_ts to a common 'ts', add is_bar as 0/1, keep the original signal timestamp in its own column, concat with ignore_index=True.
- combined = combined.sort_values(['instrument_id','ts','is_bar'], kind='mergesort') so equal keys preserve input order.
- combined[['z_ff','kts_ff']] = combined.groupby('instrument_id', sort=False)[['zscore_xs','sig_ts']].ffill()
- out = combined[combined.is_bar == 1]; set z_ff to NaN where out.ts - out.kts_ff exceeds Timedelta('10D').
- Spot-check 200 randomly chosen bar rows against a brute-force lookup over the raw sig frame.
Follow-up
- The signal file contains rows with is_backfilled = TRUE, written after as_of_date by a rerun. Does your join still produce a point-in-time panel, and what would you change?
- How would you extend this to a forward-looking join, the first score strictly after the bar, and where in a research pipeline is that the correct thing to want?
- What changes when bar_close_ts and knowledge_ts can be exactly equal because the signal is computed off that same close?
Write a Python function using numpy and pandas to clean a raw dataset,…
Write a Python function using numpy and pandas to clean a raw dataset, handle missing values, and normalize numerical features.
Approach
- Compute rates by summing numerator and denominator separately, never by averaging rates.
- State the window function and its partition and ordering out loud before writing it.
- Handle the rows that do not match: a LEFT JOIN with a NULL check is usually the question.
Follow-up
- How would you verify this result without re-running the same query?
- What breaks if events arrive late or out of order?
Implementation shortfall without double counting order-level costs
Join parent_order (order_id, side, order_qty, filled_qty, arrival_mid_px, arrival_ts, terminal_ts, algo_name, adv_20d) to execution_fill (fill_id, order_id, fill_qty, fill_px, commission_amt, exchange_fee_amt, rebate_amt, is_correction, corrects_fill_id) and report notional-weighted implementation shortfall in basis points versus arrival_mid_px, per algo_name per month, sliced by participation bucket (order_qty / adv_20d). Charge unfilled quantity at the mid prevailing at terminal_ts. State the grain of every aggregate you write.
Approach
- Collapse
execution_fillto one row perorder_idfirst:SUM(fill_qty),SUM(fill_qty * fill_px) / SUM(fill_qty)for a genuine quantity-weighted average price, and summedcommission_amt,exchange_fee_amt,rebate_amt. Only then join one-to-one back toparent_order. - Net corrections at that same stage, before any arithmetic: anti-join the originals referenced by
corrects_fill_idwhereis_correction, or sign the correction rows, and say out loud which convention this feed uses — the two give different answers and both appear in the wild. - Compute per-order shortfall with an explicit sign:
side_signis +1 for buy and buy_to_cover, -1 for sell and sell_short. Thenside_sign * (avg_fill_px - arrival_mid_px) * filled_qty + commission + fee - rebate + side_sign * (terminal_mid_px - arrival_mid_px) * (order_qty - filled_qty), all divided byorder_qty * arrival_mid_px, times 10000. - Note the precondition:
terminal_mid_pxis not a column onparent_order. It has to come from a quote source atterminal_ts, and if that source is unavailable the opportunity-cost term must be reported as missing rather than set to zero — zeroing it makes cancelling look free. - Aggregate with notional weights,
SUM(shortfall_bps * w) / SUM(w)wherew = order_qty * arrival_mid_px, not a plain AVG that lets thousands of odd lots outvote the notional that actually traded. Bucket participation with a CASE onorder_qty / NULLIF(adv_20d, 0)held in a CTE so boundaries stay reproducible.
Worked solution 35 min
- Build the fills CTE at order grain with correction netting, and assert COUNT(*) equals COUNT(DISTINCT order_id).
- Left-join it to
parent_orderso zero-fill orders survive with pure opportunity cost. - Add the side_sign CASE and the full per-order shortfall expression, keeping the four components as separate columns for debugging.
- Bucket participation, then aggregate with notional weights per (month, algo_name, bucket).
- Reconcile total report notional against total order notional for the month before showing anyone the bps.
Follow-up
- A plain
AVG(shortfall_bps)reads 4 bps and the notional-weighted number reads 19 bps. Which do you put in front of the desk, and what does the gap itself tell you? - Rerun against
interval_vwap_pxinstead of arrival. When is that the right benchmark, and what does it stop charging for? - How would you show that cost rises with participation rather than asserting it from the bucket table?
How would you optimize a slow-running pandas data pipeline that proces…
How would you optimize a slow-running pandas data pipeline that processes millions of rows of transaction data?
Approach
- State what result would change your recommendation, so the answer is falsifiable.
- Decompose the metric into the rates that drive it, and say which one you would check first.
- Name one primary metric, then the guardrail that stops it being gamed.
Follow-up
- What would you do if the primary metric and the guardrail moved in opposite directions?
- How would you detect that the metric is being gamed rather than genuinely improving?
If a client provides a highly sparse dataset with missing values, how …
If a client provides a highly sparse dataset with missing values, how would you decide whether to impute, ignore, or drop those features?
Approach
- Restate the decision this analysis has to support, and who acts on the answer.
- Fix the population and the time window before naming any metric.
- Name one primary metric, then the guardrail that stops it being gamed.
Follow-up
- What would you do if the primary metric and the guardrail moved in opposite directions?
- Which segment would you cut first, and what would that rule out?
Imagine a client wants us to optimize their retail pricing strategy. W…
Imagine a client wants us to optimize their retail pricing strategy. What data would you collect, what models would you consider, and how would you validate your pricing recommendations?
Approach
- State what result would change your recommendation, so the answer is falsifiable.
- Fix the population and the time window before naming any metric.
- Name one primary metric, then the guardrail that stops it being gamed.
Follow-up
- What would you do if the primary metric and the guardrail moved in opposite directions?
- Which segment would you cut first, and what would that rule out?
Cut variance in an execution test without touching the effect
The order-level shortfall test you sized needs nine months and the desk will not wait. For every parent order you can compute, before assignment: the impact model's predicted cost in bps from participation_rate_target, adv_20d and trailing volatility; the instrument's gics_sector_code; and the strategy's trailing sixty-day mean shortfall. Predicted and realised cost correlate at 0.55 historically. Propose a variance-reduction plan, state the reduction you expect and the resulting runtime, and draw the line between admissible and inadmissible covariates.
Approach
- Apply CUPED with predicted cost as the covariate: Y_adj = Y - theta * (X - mean(X)), with theta = Cov(Y, X) / Var(X) estimated on the pooled experiment sample. The adjusted estimator targets the same estimand without bias because X is independent of assignment, and its variance falls by the factor 1 - rho^2.
- Put a number on it. At rho = 0.55 the reduction is 1 - 0.3025, so about 30 percent of the variance and therefore 30 percent of the sample size. State that this is a ceiling: rho estimated in-sample overstates the reduction you will realise, so quote the out-of-sample correlation if you have one.
- Draw the admissibility line sharply. A covariate is admissible only if it is fixed before randomisation. Predicted cost, adv_20d, participation_rate_target, order_qty, decision_mid_px, gics_sector_code and the strategy's trailing shortfall all qualify. Realised participation rate, realised fill count, interval_vwap_px, terminal_ts and anything read from execution_fill do not, because the treatment changes them, and conditioning on a post-treatment variable introduces a bias that no amount of additional sample removes.
- Add stratified assignment on the same information, bucketed as participation quintile by adv_20d quintile, so balance is enforced rather than hoped for. Stratification and CUPED compete for the same variance; running both buys a little extra, mostly as insurance against a bad draw inside a thin stratum rather than as a further cut to the standard error.
- Pre-register how theta is estimated and what the strata are. Choosing theta after seeing the treatment effect turns CUPED into a specification search with a respectable name attached to it.
Worked solution 30 min
- Build a covariate table keyed on order_id containing only pre-assignment fields: predicted cost, adv_20d, participation_rate_target, order_qty, gics_sector_code and trailing sixty-day strategy shortfall.
- On a historical sample that precedes the experiment, regress realised shortfall on predicted cost, confirm rho is near 0.55 out of sample, and record theta-hat = Cov / Var.
- Compute the variance reduction 1 - rho^2 and the revised per-arm sample size and runtime.
- Once the test is running, verify that mean predicted cost is statistically indistinguishable across arms. If it is not, the randomisation is broken and CUPED will quietly paper over it.
- Report the adjusted and unadjusted effects side by side, along with the realised variance reduction.
Follow-up
- What goes wrong if theta is estimated separately within each arm rather than pooled?
- Shortfall is heavy tailed. Does winsorising before CUPED help or hurt, and what does it do to the estimand you are reporting?
- Which is worth more here: CUPED at rho = 0.55, or moving the decision from the equal-weighted to the notional-weighted mean?
Return dispersion widened inside one strategy composite
Trailing-12-month net returns for accounts running one strategy used to sit within about 40 bps of each other. This quarter the cross-sectional standard deviation is 210 bps and the AUM-weighted mandate success rate fell. The investment team insists the model is identical across accounts. You have position_daily (business_date, account_id, strategy_id, instrument_id, market_value_base, weight_pct_nav, is_restricted, fx_rate_to_base) and account_mandate (account_id, funded_date, inception_date, status, target_gross_exposure_pct, max_single_name_weight_pct, base_currency, mgmt_fee_bps, effective_from, effective_to). Explain the dispersion with an ordered checklist and say which part is a problem.
Approach
- Rank accounts by trailing-12-month net return and inspect the tail before averaging anything. A standard deviation is a distribution statistic and two accounts out of forty can produce it; the number alone does not say whether the cause is systemic or concentrated.
- Cut by months since funded_date and by status. An account in 'ramping' holds cash and sits below target_gross_exposure_pct, so it earns a diluted version of the strategy's return. In a rising market that reads as underperformance and in a falling one as outperformance, and both are mechanical rather than informative.
- Compute realized gross exposure per account-day from position_daily, as the sum of absolute market_value_base over NAV, and compare it with target_gross_exposure_pct from the account_mandate version valid on that business_date. Join on the effective_from and effective_to range, not on the current row, because mandate terms change mid-life and the current row would apply today's target to last year's book.
- Sort the remaining explanations into expected and not expected. Names excluded by is_restricted, base_currency differences moving through fx_rate_to_base, and mgmt_fee_bps differences on a net-of-fee metric are all expected. A weight breaching max_single_name_weight_pct, or an account holding instruments the others do not, is not.
- Report dispersion decomposed by cause with dollars attached. The client question is never why sigma is 210 bps; it is why this account returned less than the one on the last page.
Follow-up
- Two accounts funded the same day diverge by 90 bps and both reached target exposure inside 20 trading days. Where do you look next?
- The AUM-weighted success rate only counts accounts with 36 months of history. How does that interact with what you just found, and does it flatter the number or penalise it?
- How would you present cash drag to a client so it reads as a fact about funding rather than an excuse?
For someone who has spent the last year in notebooks, dashboards or modelling work and has not written raw SQL under time pressure. The first four days rebuild query fluency against a fixture you control and can verify by hand; the last three attach that fluency to the rest of the loop.
Prepare, practise & reflect
One practical outcome each day. Spend longer where you need it.
0 / 7 done01Build a fixture you can check answers against
- Create a local Postgres or SQLite database with four tables (users, sessions, events, orders) holding roughly 200 rows you generated yourself, so you know the contents well enough to predict every result.
- Deliberately seed the cases that break queries: a user with no sessions, a session with no events, two orders sharing a timestamp, a NULL in one join key, and one duplicated user row.
- Before writing any SQL, hand-compute five answers on paper (how many users placed at least one order, median orders per ordering user, and three others) and save them as the ground truth for the week.
Deliverable: A one-command seed script plus a text file of five hand-computed answers to grade every later query against.
Practice prompt ↗Practice prompt ↗Practice prompt ↗Worked solution ↗02Joins, filters and NULL semantics
- Answer "which users have no orders" three ways (LEFT JOIN with IS NULL, NOT EXISTS, NOT IN) and confirm that the NOT IN version returns zero rows once the subquery contains a NULL, because the comparison is never TRUE.
- Reproduce the LEFT JOIN that silently collapses to an inner join by putting a right-table predicate in WHERE, then fix it by moving the predicate into the ON clause, and record both row counts.
- Create a fan-out bug on purpose by joining orders to order_items and summing the order total, then correct it with a pre-aggregated subquery and explain in one line which table changed the grain.
Deliverable: One annotated .sql file holding the three join traps, each with the wrong result and the corrected result side by side.
Practice prompt ↗Practice prompt ↗03Window functions and frames
- Write three window queries against the fixture: a running order total per user, the rank of each order within its user by value, and the day gap to that user's previous order, then check each against the day-one ground truth.
- Run ROW_NUMBER, RANK and DENSE_RANK over a column containing ties, print all three side by side, and write one sentence on when each is the correct choice.
- Switch one query from the default frame (RANGE BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW, which is what you get when ORDER BY is present and no frame is written) to ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW, and explain why the output differs only when the ORDER BY column has duplicates.
Deliverable: Three verified window queries plus a short note explaining the RANGE versus ROWS difference in your own words.
Practice prompt ↗Practice prompt ↗04The four analytical query patterns
- Write a monthly retention grid: first order month per user, then months-since-first as the column, and verify that month zero equals the cohort size exactly.
- Sessionize the events table under a 30-minute inactivity rule using LAG plus a cumulative sum over a new-session flag.
- Build a four-step funnel that counts distinct users rather than events at each step, and state the rule you applied to a user who reaches step three without ever logging step two.
Deliverable: One file with the retention, sessionization and funnel patterns, each carrying a one-line note on the assumption it bakes in.
Practice prompt ↗Practice prompt ↗Worked solution ↗05Write SQL the way you will have to write it live
- Set a 12-minute timer and solve three medium prompts in a plain editor with no execution and no autocomplete, then run them and tally syntax errors separately from logic errors.
- Narrate one solution aloud while writing it, stating the grain of each intermediate result (one row per user, one row per user-day) before you type its body.
- Rewrite your slowest solution as a CTE chain where every CTE name states its grain, and time yourself re-solving it from blank.
Deliverable: A recording of one narrated solution plus an error tally that separates syntax from logic.
Practice prompt ↗Practice prompt ↗06One day for everything that is not SQL
- Write the preconditions of the two-sample t-test from memory, then check them: independent observations, and a difference in means whose sampling distribution is approximately normal, which at large sample sizes follows from the central limit theorem rather than from normality of the raw values.
- Write the difference between an odds ratio from logistic regression and a relative risk, and state the condition under which the two are close (low outcome prevalence).
- Prepare a 90-second answer to "how would you know this model is any good" that names the metric, the baseline you would beat, and the cost of the errors you care about.
Deliverable: One page of notes covering test preconditions, the odds-ratio caveat and the model-quality answer.
Practice prompt ↗Practice prompt ↗07Full loop rehearsal
- Run a 45-minute mock with someone willing to interrupt: 20 minutes of SQL, 15 minutes defining a metric, 10 minutes on a past project.
- Re-solve from blank the two queries you were slowest on this week and compare the times against day five.
- Write a five-line answer to "walk me through a project" that puts a number in the first sentence and names the decision the work changed.
Deliverable: Mock feedback notes plus a timed project narrative you can deliver without reading it.
Practice prompt ↗Practice prompt ↗Worked solution ↗Expand any day for tasks and deliverables. Your progress is saved on this device.
Nearly every data role forces a trade between the analysis you want and the one that fits the decision window. Prepare a case where you deliberately shipped something less rigorous, named the weakness to the person relying on it, and said what would change your answer. The naming is the part interviewers listen for.
How do you handle multicollinearity in a high-dimensional dataset when…
How do you handle multicollinearity in a high-dimensional dataset when building a linear model?
Approach
- Close with what you would do differently, concretely.
- Pick a story where you drove the decision, not one where you observed it.
- Quantify the outcome, including what you would not claim credit for.
Follow-up
- How did you know the outcome was caused by your change?
- What would you do differently if you ran that project again?
Writing an impact statement that survives a hostile reading
Write your own annual impact statement. Your work: a market-impact recalibration the desk adopted in March; a signal you researched that a portfolio manager sized and traded; and a rewrite of the nightly position reconciliation that reduced unreconciled rows in position_daily. Realized implementation shortfall fell from 21 bps to 14 bps after March. Market volatility also fell over the same period. State what you added, in basis points where the attribution supports it, and be explicit about where it does not.
Approach
- What is probed: whether you can separate correlation from contribution when the correlation favours you, which is the one place almost everyone's standards slip.
- Build a counterfactual for the shortfall claim instead of a before-and-after. Shortfall scales with volatility, so a pre and post comparison across a regime change partly measures the market. Use orders that kept the old routing or the old parameters as a control over the same window, matched on participation bucket (order_qty over adv_20d) and side, and report the difference-in-differences rather than the raw 7 bps.
- State the part you cannot claim before anyone asks. The signal was sized by the portfolio manager, so its P and L is a joint product. Claim the research decision itself: what you tested, what you rejected, the number of configurations tried, and the standard error you attached. Volunteering the boundary is what makes the claims inside it credible.
- Give the reconciliation work a number that is not basis points. Report unreconciled and break rows in position_daily before and after, plus the downstream consequence: marks that fell back to stale_prior_day, and client reports restated. Inventing a basis-point figure for operational work costs you the basis-point figures that are real.
- Write a falsifier next to each claim, naming the evidence that would show you added nothing. A reviewer who watches you name your own weakest claim stops auditing the strong ones.
Follow-up
- Your control group is 8 percent of order flow. Is the difference-in-differences credible at that size, and what would you need to make it so?
- The signal lost money this year. Does it appear in the statement, and in what form?
- What did you get wrong this year, and what did it cost?
Defending a backtest correction that removes an allocated strategy
A colleague's cross-sectional equity signal received capital last month on a backtest showing annualized Sharpe 1.6 over three years. Reproducing it, you find the panel filters signal_score on as_of_date rather than knowledge_ts. Rerunning with the knowledge_ts predicate, holding universe_id, date range, cost model and rebalance schedule fixed, gives Sharpe 0.5 and moves mean daily IC from 0.041 to 0.012. The colleague is senior and presented the original result. You have one meeting with the research lead and the portfolio manager. Deliver a recommendation on whether the allocation stands, and the evidence behind it.
Approach
- What is probed: whether a quantitative objection survives social cost. Lead with the defect and the single-variable reproduction, never with a judgement about the colleague. The claim under test is one predicate, not a person's competence.
- Rerun both versions from one code path with one line changed, and say so explicitly. Holding universe_id, date range, cost model and rebalance schedule fixed leaves the 1.1 Sharpe gap exactly one candidate cause, which is what makes the result arguable on its merits instead of on whose code is trusted.
- Pair the comparison before quoting any error bar. For modest Sharpe ratios the annualized standard error of a Sharpe estimate is approximately 1 over the square root of the number of years, so three years of daily data gives roughly 0.58 and two marginal estimates 1.1 apart are only about two standard errors apart. But the two runs are the same returns except where the leak bites, so test the daily difference series directly: its standard error is far smaller, and the pairing is what turns a marginal result into a decisive one.
- Exhibit the mechanism, not just the size. Rank instrument-days by their contribution to the return difference between the two runs and show that the top contributors carry is_backfilled TRUE or coverage_flag 'stale', with knowledge_ts postdating as_of_date by the vendor's restatement lag. A named mechanism is falsifiable; a Sharpe delta alone becomes an argument about your code.
- Bring a decision rather than only a finding: the position size the corrected Sharpe supports, and an untouched out-of-sample window that would settle it either way. Being right with no path forward is how a correct objection gets overruled.
Follow-up
- Your colleague reruns it and gets 0.9 rather than 0.5. What do you do with the discrepancy before the meeting?
- The strategy is up since funding. Does live P and L change your recommendation, and how much of it would?
- What would have caught this before the allocation, and why did the existing review not catch it?
- 01
How do you handle multicollinearity in a high-dimensional dataset when building a linear model?
- 02
Write your own annual impact statement. Your work: a market-impact recalibration the desk adopted in March; a signal you researched that a portfolio manager sized and traded; and a rewrite of the nightly position reconciliation that reduced unreconciled rows in position_daily. Realized implementation shortfall fell from 21 bps to 14 bps after March. Market volatility also fell over the same period. State what you added, in basis points where the attribution supports it, and be explicit about where it does not.
- 03
A colleague's cross-sectional equity signal received capital last month on a backtest showing annualized Sharpe 1.6 over three years. Reproducing it, you find the panel filters signal_score on as_of_date rather than knowledge_ts. Rerunning with the knowledge_ts predicate, holding universe_id, date range, cost model and rebalance schedule fixed, gives Sharpe 0.5 and moves mean daily IC from 0.041 to 0.012. The colleague is senior and presented the original result. You have one meeting with the research lead and the portfolio manager. Deliver a recommendation on whether the allocation stands, and the evidence behind it.
Is this an official QUANTCO interview guide?
No. It is PracHub's own research and practice material for the Data Scientist role at QUANTCO. Rounds and questions reflect what candidates have reported, not a process QUANTCO has published, and they change over time. Confirm the current format and scope with your recruiter.
PracHub interview research ↗How difficult is the QUANTCO Data Scientist interview process?
The process is highly rigorous and rated as average to difficult by most candidates. The difficulty stems from the depth of the theoretical math and statistics questions, combined with the comprehensive nature of the multi-hour coding and presentation challenge. Thorough preparation of fundamentals is essential.
PracHub interview research ↗What is the coding environment like for the data challenge?
You will write Python code, primarily utilizing pandas and numpy for data manipulation and scikit-learn for modeling. The focus is on clean, structured, and reproducible code rather than using highly complex deep learning frameworks.
PracHub interview research ↗Why does QUANTCO focus so heavily on linear models?
Linear models are highly interpretable, mathematically robust, and form the foundation of many complex pricing and optimization systems. QUANTCO values deep mastery of these models because they are easier to validate, audit, and explain to enterprise clients.
PracHub interview research ↗How long does the entire interview process take?
The process typically takes between 4 to 8 weeks from the initial HR screen to the final decision, depending on interviewer availability and the location of the office you are applying to.
PracHub interview research ↗Sources & methodology 3 sources ↗
No official company page is cited. Rounds and questions come from candidate reports and PracHub editorial material; each source shows the date it was read.
- 01PracHub interview research ↗
PracHub editorial research into this company and role, maintained with this guide. Candidate-reported, not an employer publication.
PracHub page · Accessed 2026-09-22 - 02PracHub Data Scientist practice ↗
Cross-company practice questions for this role.
PracHub page · Accessed 2026-09-22 - 03PracHub interview preparation framework ↗
The framework the preparation plan follows.
PracHub page · Accessed 2026-09-22