0% found this document useful (0 votes)
2 views43 pages

QuantPro Week10 Complete

ff
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
2 views43 pages

QuantPro Week10 Complete

ff
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd

QUANT PRO WEEK 10 | Days 71-78 | ELITE LAYER

Advanced Quant Finance Course Time Series | Cointegration | Microstructure | Execution | Final System

QUANT
PRO
Advanced Quant Finance Course
WEEK 10 — Days 71 to 78 — THE ELITE LAYER

8 ELITE COURSE CAREER


DAYS LAYER COMPLETE LAUNCH

Day 71: Time Series Core (Stationarity, ADF, ARIMA) · Day 72: Cointegration Deep Dive (Kalman Filter) · Day
73: Advanced Portfolio Optimisation (Risk Parity, Black-Litterman) · Day 74: Market Microstructure · Day 75:
Execution Algorithms (VWAP/TWAP) · Day 76: Code Architecture · Day 77: Final System Part 1 · Day 78: Final
System Part 2 + SQL Master Guide + Max Output Tips

What Weeks 1-9 gave you. Week 10 adds the elite mathematical
A complete production quant system: live layer.
pipeline, ML alpha, options strategies, Time series stationarity, Kalman Filter
professional risk management, cloud cointegration, robust portfolio optimisation,
deployment, interview readiness, and a market microstructure, VWAP/TWAP
career plan. execution, SQL mastery, and the final
complete modular system. Plus the full SQL
guide and maximum-output tips that close
the course.

Quant Pro | Advanced Quant Finance Course | Week 10 — Elite Layer Page 1
QUANT PRO WEEK 10 | Days 71-78 | ELITE LAYER

Advanced Quant Finance Course Time Series | Cointegration | Microstructure | Execution | Final System

QUANT PRO
Advanced Quant Finance Course
WEEK 10 — Days 71 to 78 — THE ELITE LAYER
Time Series · Cointegration + Kalman · Robust Portfolio Optimisation · Market Microstructure · VWAP/TWAP Execution
· Code Architecture · SQL Mastery · Final System

8 KALMAN SQL COURSE


DAYS FILTER MASTERY COMPLETE

Week 10 is the content that separates a strong junior from a genuine quant practitioner. Every topic here is
tested in senior interviews at global firms — Jane Street, Citadel, WorldQuant — and used daily on
professional quant desks. Stationarity and ARIMA underpin all time-series modelling. The Kalman Filter is
the correct way to track a changing hedge ratio in pairs trading. Risk parity and Black-Litterman fix the
critical failures of basic Markowitz. Market microstructure explains why your live trades fill worse than your
backtest. VWAP and TWAP execution are how institutional desks minimise market impact on large orders.
The final days complete the modular system, add the full SQL guide, and close with a comprehensive set of
tips, tricks, and resources to maximise what you get from this entire course.

WEEK 10 AT A GLANCE
Day Topic Key Skill Project Output

71 Time Series Core Stationarity, ADF test, ARIMA forecast vs naive


ACF/PACF, ARIMA fit benchmark chart

72 Cointegration Deep Dive Engle-Granger, half-life, Dynamic hedge ratio chart on


Kalman Filter hedge ratio TCS-INFY spread

73 Advanced Portfolio Risk parity, Black-Litterman, Risk parity vs Markowitz


Optimisation resampled frontier weight comparison

74 Market Microstructure Order book, adverse selection, Amihud illiquidity ratio for
Kyle Lambda, Amihud 5 NSE stocks

75 Execution Algorithms TWAP, VWAP, implementation VWAP schedule for 10,000


shortfall, Almgren-Chriss share NIFTY order

76 Code Architecture + SQL Package structure, type hints, Refactored strategy class +
Mastery pytest + full SQL guide SQL query suite

Quant Pro | Advanced Quant Finance Course | Week 10 — Elite Layer Page 2
QUANT PRO WEEK 10 | Days 71-78 | ELITE LAYER

Advanced Quant Finance Course Time Series | Cointegration | Microstructure | Execution | Final System

77 Final Project Part 1 Connect all 10-week components, Complete system running
integration test end-to-end live

78 Final Project Part 2 + Max GitHub polish, SQL deep dive, Professional portfolio +
Output Guide tips & tricks, resources complete reference guide

Quant Pro | Advanced Quant Finance Course | Week 10 — Elite Layer Page 3
QUANT PRO WEEK 10 | Days 71-78 | ELITE LAYER

Advanced Quant Finance Course Time Series | Cointegration | Microstructure | Execution | Final System

DAY
Time Series Core

71 Stationarity, ADF test, ACF/PACF plots, and ARIMA — the mathematical foundation under every
quant model

Why Stationarity Is the Most Important Concept in Time Series


A stationary time series has a constant mean, constant variance, and no trend over time. This sounds
academic but it has one brutal practical consequence: if you run correlation, regression, or any statistical
model on non-stationary data, your results are completely meaningless. You can find a 0.95 correlation
between two completely unrelated series simply because both trend upward. This is called spurious
regression and it has destroyed countless trading strategies built by people who skipped this topic.

> REAL-WORLD ANALOGY


Imagine testing whether chocolate consumption predicts Nobel Prize winners per country. Both have been
rising over decades. Their correlation is high — but it is entirely spurious. Both are driven by GDP growth (a
third variable), not by any causal relationship. Stock price levels are exactly like this. Two trending price series
will appear correlated even if the companies have nothing to do with each other. The fix is to use returns
(stationary) instead of price levels (non-stationary).

ADF Test — The Stationarity Detector


AUGMENTED DICKEY-FULLER (ADF) TEST

Null hypothesis: series has a unit root = is NON-STATIONARY

p-value > 0.05 -> Fail to reject null -> SERIES IS NON-STATIONARY
Cannot use in regression directly
Fix: take the first difference (returns)

p-value < 0.05 -> Reject null -> SERIES IS STATIONARY


Safe to use in statistical models

TYPICAL RESULTS ON NSE DATA:


TCS closing price levels : ADF p = 0.82 -> NON-STATIONARY
TCS daily returns (%) : ADF p = 0.00 -> STATIONARY
TCS log returns : ADF p = 0.00 -> STATIONARY
TCS volume (raw) : ADF p = 0.43 -> NON-STATIONARY
TCS volume change % : ADF p = 0.00 -> STATIONARY

RULE: always run ADF before any regression or correlation on financial data.
If p > 0.05: difference the series first. Then re-test.

ACF and PACF — Reading the Autocorrelation Structure


ACF = Autocorrelation Function: corr(series_t, series_{t-k}) for each lag k

Quant Pro | Advanced Quant Finance Course | Week 10 — Elite Layer Page 4
QUANT PRO WEEK 10 | Days 71-78 | ELITE LAYER

Advanced Quant Finance Course Time Series | Cointegration | Microstructure | Execution | Final System

PACF = Partial ACF: correlation at lag k after removing all shorter lags

READING THE PLOTS:


Bars outside dashed confidence band -> statistically significant autocorrelation
Dashed band threshold = +/- 1.96 / sqrt(n)

PATTERN -> MODEL SUGGESTION:


ACF cuts off sharply after lag q -> MA(q) component
PACF cuts off sharply after lag p -> AR(p) component
Both decay slowly -> ARIMA(p,d,q)

FOR DAILY STOCK RETURNS IN PRACTICE:


Most large-cap NSE stocks show almost no significant autocorrelation.
This is expected: markets are nearly efficient at daily frequency.
ACF and PACF of squared returns (volatility) DO show strong patterns.
This is why GARCH (not ARIMA) is the right model for volatility.

WHERE ARIMA GENUINELY HELPS IN FINANCE:


- Macro indicators: monthly CPI, quarterly GDP, repo rate forecasting
- Order flow imbalance (intraday)
- Trading volume forecasting
- Spread modelling in pairs trading (the spread between cointegrated stocks)

Python Code — Day 71: Stationarity Tests and ARIMA


import pandas as pd, numpy as np
import [Link] as plt
from [Link] import adfuller, acf, pacf
from [Link] import ARIMA
from [Link] import mean_absolute_error
import warnings; [Link]("ignore")

df = pd.read_csv("[Link]")
df = df[df["SYMBOL"]=="TCS"].sort_values("DATE1").reset_index(drop=True)
df["DATE1"] = pd.to_datetime(df["DATE1"])
prices = df["CLOSE"]
returns = prices.pct_change().dropna() * 100

# ■■ 1. ADF Tests on price levels vs returns ■■■■■■■■■■


def adf_report(series, label):
res = adfuller([Link](), autolag="AIC")
stat, pval = res[0], res[1]
status = "STATIONARY ✓" if pval < 0.05 else "NON-STATIONARY ✗"
print(f" {label:<35} ADF={stat:7.3f} p={pval:.4f} {status}")

print("=== ADF STATIONARITY TESTS ===")


adf_report(prices, "TCS Price Levels")
adf_report(returns, "TCS Daily Returns (%)")
adf_report([Link](prices), "TCS Log Price")
adf_report([Link](prices).diff().dropna(), "TCS Log Return")

# ■■ 2. ACF / PACF visual ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■

Quant Pro | Advanced Quant Finance Course | Week 10 — Elite Layer Page 5
QUANT PRO WEEK 10 | Days 71-78 | ELITE LAYER

Advanced Quant Finance Course Time Series | Cointegration | Microstructure | Execution | Final System

ret_arr = [Link]
nlags = 25
acf_v = acf(ret_arr, nlags=nlags, fft=True)
pacf_v = pacf(ret_arr, nlags=nlags)
ci = 1.96 / [Link](len(ret_arr))

fig, axes = [Link](1, 2, figsize=(13,5))


for ax, vals, title, color in [
(axes[0], acf_v, "ACF — TCS Daily Returns", "royalblue"),
(axes[1], pacf_v, "PACF — TCS Daily Returns", "seagreen"),
]:
[Link](range(len(vals)), vals, color=color, alpha=0.7)
[Link]( ci, color="red", linestyle="--", lw=1, label="95% CI")
[Link](-ci, color="red", linestyle="--", lw=1)
[Link]( 0, color="black", lw=0.8)
ax.set_title(title, fontweight="bold")
ax.set_xlabel("Lag (days)"); [Link](fontsize=8)
[Link](True, alpha=0.3)
[Link]("Autocorrelation Analysis — bars beyond dashed lines are significant",
fontweight="bold")
plt.tight_layout()
[Link]("acf_pacf.png", dpi=150, bbox_inches="tight")
[Link]()

# ■■ 3. ARIMA Forecast vs Naive Benchmark ■■■■■■■■■■■■■


train_arr = ret_arr[:-30]
test_arr = ret_arr[-30:]

model_arima = ARIMA(train_arr, order=(1,0,1)).fit()


fc_arima = model_arima.forecast(steps=30)
fc_naive = [Link](30, train_arr.mean()) # predict mean every day

mae_arima = mean_absolute_error(test_arr, fc_arima)


mae_naive = mean_absolute_error(test_arr, fc_naive)

print(f"\n=== ARIMA(1,0,1) vs Naive Mean Forecast ===")


print(f"ARIMA MAE : {mae_arima:.4f}%")
print(f"Naive MAE : {mae_naive:.4f}%")
improvement = (1 - mae_arima/mae_naive)*100
print(f"Improvement : {improvement:.1f}%")
print("Takeaway: small improvement is normal — efficient markets have low autocorrelation")

# Plot actual vs forecast


fig, ax = [Link](figsize=(12,5))
[Link](range(30), test_arr, color="royalblue", lw=2, label="Actual")
[Link](range(30), fc_arima, color="seagreen", lw=1.5, label="ARIMA(1,0,1)")
[Link](range(30), fc_naive, color="tomato", lw=1.5, linestyle="--", label="Naive Mean")
[Link](0, color="black", lw=0.8)
ax.set_title("ARIMA vs Naive Forecast — TCS 30-Day Test Period", fontweight="bold")
ax.set_xlabel("Day"); ax.set_ylabel("Return (%)")
[Link](); [Link](True, alpha=0.2)
plt.tight_layout()

Quant Pro | Advanced Quant Finance Course | Week 10 — Elite Layer Page 6
QUANT PRO WEEK 10 | Days 71-78 | ELITE LAYER

Advanced Quant Finance Course Time Series | Cointegration | Microstructure | Execution | Final System

[Link]("arima_forecast.png", dpi=150, bbox_inches="tight")


[Link]()

Day 71 Key Takeaways


• Non-stationary price levels produce spurious correlations — always use returns in any statistical model.
• ADF p-value below 0.05 confirms stationarity — run this test before any regression or correlation on
financial data.
• Stock returns show almost no ACF/PACF structure — markets are nearly efficient at daily frequency.
• ARIMA improvements over naive forecasting for daily returns are small — use GARCH for volatility, not
ARIMA.
• ARIMA is genuinely useful for: macro time series (CPI, GDP), trading volume forecasting, and spread
modelling.

Quant Pro | Advanced Quant Finance Course | Week 10 — Elite Layer Page 7
QUANT PRO WEEK 10 | Days 71-78 | ELITE LAYER

Advanced Quant Finance Course Time Series | Cointegration | Microstructure | Execution | Final System

DAY

Cointegration Deep Dive

72 Engle-Granger test, half-life of mean reversion, and Kalman Filter dynamic hedge ratio

Why Cointegration Is More Powerful Than Correlation


Week 4 introduced pairs trading using a fixed OLS hedge ratio. Day 27 extended it with z-score signals.
This day adds the mathematical rigour that makes the strategy genuinely professional. The key insight: the
hedge ratio between two cointegrated stocks is not constant over time. TCS and INFY are both IT
companies, but their relative valuations, revenue mix, and market positioning shift year by year. A hedge
ratio computed in 2020 can be 30-40% wrong by 2024. The Kalman Filter solves this.

The Engle-Granger Test and Half-Life


COINTEGRATION vs CORRELATION

Correlation: both series move in the same direction frequently.


Correlation is not stable — it can break down at any time.

Cointegration: the SPREAD between the two series is stationary.


Even though each series individually is non-stationary (trending),
their linear combination reverts to a stable mean.
This is much more powerful — it means there is a long-run equilibrium.

ENGLE-GRANGER TWO-STEP TEST:


Step 1: Regress series Y on series X -> get hedge ratio beta
Step 2: Run ADF test on residuals (Y - beta*X)
If residuals are stationary (p < 0.05) -> cointegrated!

HALF-LIFE OF MEAN REVERSION:


How quickly does the spread return to zero after a deviation?
Step 1: Regress delta_spread(t) = lambda * spread(t-1) + error
Step 2: half_life = -ln(2) / lambda

Half-life < 5 days -> too fast, hard to execute profitably


Half-life 5-30 days -> sweet spot for daily signal trading
Half-life > 60 days -> too slow, large drawdowns, high margin cost

TCS-INFY typical half-life: 8-15 days (excellent for pairs trading)

Kalman Filter — Dynamic Hedge Ratio


The Kalman Filter is a mathematical algorithm that continuously updates its estimate of a hidden state
(here: the hedge ratio) as new observations arrive. It is the optimal linear estimator when both the state and
observations have Gaussian noise. In pairs trading, it gives us a hedge ratio that adapts in real time to
changing market conditions — far superior to the static OLS ratio.

Quant Pro | Advanced Quant Finance Course | Week 10 — Elite Layer Page 8
QUANT PRO WEEK 10 | Days 71-78 | ELITE LAYER

Advanced Quant Finance Course Time Series | Cointegration | Microstructure | Execution | Final System

Python Code — Day 72: Kalman Filter Pairs Trading


import pandas as pd, numpy as np
import [Link] as plt
import [Link] as sm
from [Link] import adfuller, coint
import warnings; [Link]("ignore")

df = pd.read_csv("[Link]")
df["DATE1"] = pd.to_datetime(df["DATE1"])
df = df.sort_values(["SYMBOL","DATE1"])

tcs = df[df["SYMBOL"]=="TCS"].set_index("DATE1")["CLOSE"]
infy = df[df["SYMBOL"]=="INFY"].set_index("DATE1")["CLOSE"]
pair = [Link]({"TCS":tcs,"INFY":infy}).dropna()

# ■■ Step 1: Engle-Granger cointegration test ■■■■■■■■■


score, pval, _ = coint(pair["TCS"], pair["INFY"])
print(f"Cointegration p-value: {pval:.4f}",
"-> COINTEGRATED" if pval < 0.05 else "-> NOT cointegrated")

# ■■ Step 2: Static OLS hedge ratio ■■■■■■■■■■■■■■■■■■■


X = sm.add_constant(pair["INFY"])
ols_res = [Link](pair["TCS"], X).fit()
beta_static = ols_res.params["INFY"]
spread_static = pair["TCS"] - beta_static * pair["INFY"]
print(f"Static hedge ratio: {beta_static:.4f}")

# ■■ Step 3: ADF on static spread ■■■■■■■■■■■■■■■■■■■■■


adf_res = adfuller(spread_static)
print(f"Spread ADF p-value: {adf_res[1]:.4f}",
"STATIONARY" if adf_res[1] < 0.05 else "NON-STATIONARY")

# ■■ Step 4: Half-life of mean reversion ■■■■■■■■■■■■■■


delta_spread = spread_static.diff().dropna()
spread_lag = spread_static.shift(1).dropna()
idx = delta_spread.[Link](spread_lag.index)
reg_hl = [Link](delta_spread.loc[idx].values,
spread_lag.loc[idx].values).fit()
lam = reg_hl.params[0]
half_life = -[Link](2) / lam if lam < 0 else [Link]
print(f"Half-life of mean reversion: {half_life:.1f} days")

# ■■ Step 5: Kalman Filter dynamic hedge ratio ■■■■■■■■■


n = len(pair)
delta = 1e-5 # process noise — smaller = slower adaptation
Vw = delta / (1 - delta) * [Link](2)
Ve = 0.001 # observation noise

beta_kf = [Link](n) # stores dynamic hedge ratio


P = [Link]((2,2)) # error covariance matrix
theta = [Link]([0.0, beta_static]) # initial state: [intercept, beta]

for t in range(n):

Quant Pro | Advanced Quant Finance Course | Week 10 — Elite Layer Page 9
QUANT PRO WEEK 10 | Days 71-78 | ELITE LAYER

Advanced Quant Finance Course Time Series | Cointegration | Microstructure | Execution | Final System

y = pair["TCS"].iloc[t]
F = [Link]([1.0, pair["INFY"].iloc[t]])
# Predict
P = P + Vw
# Innovation
e = y - F @ theta
S = F @ P @ F + Ve
# Kalman gain
K = (P @ F) / S
# Update
theta = theta + K * e
P = P - [Link](K, F) @ P
beta_kf[t] = theta[1]

beta_kf_series = [Link](beta_kf, index=[Link])


spread_kf = pair["TCS"] - beta_kf_series * pair["INFY"]

# ■■ Step 6: Z-score signals ■■■■■■■■■■■■■■■■■■■■■■■■■■■


def zscore(s, w=30):
return (s - [Link](w).mean()) / [Link](w).std()

z_static = zscore(spread_static)
z_kf = zscore(spread_kf)

signal_kf = [Link](0, index=[Link])


signal_kf[z_kf < -2] = 1 # LONG spread (TCS cheap vs INFY)
signal_kf[z_kf > 2] = -1 # SHORT spread (TCS expensive vs INFY)

# ■■ Plot ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
fig, axes = [Link](3, 1, figsize=(13,11), sharex=True)

axes[0].plot(beta_kf_series, color="royalblue", lw=1.8, label="Kalman Hedge Ratio")


axes[0].axhline(beta_static, color="tomato", lw=1.5, linestyle="--",
label=f"Static OLS = {beta_static:.3f}")
axes[0].set_title("Hedge Ratio: Kalman Filter vs Static OLS", fontweight="bold")
axes[0].legend(fontsize=8); axes[0].grid(True, alpha=0.2)

axes[1].plot(z_kf.values, color="royalblue", lw=1.5, label="Z-score (Kalman)")


axes[1].plot(z_static.values, color="tomato", lw=1, alpha=0.6, label="Z-score (Static)")
axes[1].axhline( 2, color="darkred", linestyle="--", lw=1, label="Short entry +2")
axes[1].axhline(-2, color="darkgreen", linestyle="--", lw=1, label="Long entry -2")
axes[1].axhline( 0, color="black", lw=0.8)
axes[1].set_title(f"Spread Z-score | Half-life = {half_life:.1f} days", fontweight="bold")
axes[1].legend(fontsize=7); axes[1].grid(True, alpha=0.2)

colors_sig = ["seagreen" if v>0 else "tomato" if v<0 else "lightgray" for v in signal_kf.values]
axes[2].bar(range(len(signal_kf)), signal_kf.values, color=colors_sig, alpha=0.7)
axes[2].set_title("Trading Signal: +1 = Long Spread | -1 = Short Spread", fontweight="bold")
axes[2].set_ylabel("Signal"); axes[2].grid(True, alpha=0.2)

[Link]("TCS-INFY Kalman Filter Pairs Trading", fontweight="bold")


plt.tight_layout()
[Link]("kalman_pairs.png", dpi=150, bbox_inches="tight")
[Link]()

Quant Pro | Advanced Quant Finance Course | Week 10 — Elite Layer Page 10
QUANT PRO WEEK 10 | Days 71-78 | ELITE LAYER

Advanced Quant Finance Course Time Series | Cointegration | Microstructure | Execution | Final System

Day 72 Key Takeaways


• Cointegration means the SPREAD is stationary — far more reliable for trading than simple price
correlation.
• Half-life between 5 and 30 days is the sweet spot — fast enough to profit, slow enough to execute.
• The Kalman Filter hedge ratio adapts continuously — it is always more accurate than the static OLS ratio
computed once.
• A declining or erratic Kalman beta signals cointegration breakdown — stop trading the pair if beta drifts
above 2x original.
• Always re-confirm cointegration quarterly — pairs that were cointegrated for 3 years can break down in
weeks.

Quant Pro | Advanced Quant Finance Course | Week 10 — Elite Layer Page 11
QUANT PRO WEEK 10 | Days 71-78 | ELITE LAYER

Advanced Quant Finance Course Time Series | Cointegration | Microstructure | Execution | Final System

DAY

Advanced Portfolio Optimisation

73 Risk parity, Black-Litterman, and resampled efficient frontier — fix the failures of basic Markowitz

The Three Failures of Basic Markowitz


The efficient frontier from the original course works in theory but fails in practice for three reasons. First: tiny
changes in expected return estimates produce wildly different optimal weights (input sensitivity). Second:
optimal weights tend to concentrate in one or two assets with near-zero allocation to everything else. Third:
the covariance matrix estimated from historical data contains enormous estimation error that the optimizer
exploits. These are not minor issues — they make raw Markowitz unusable for live trading.

Solution 1 — Risk Parity


RISK PARITY: ALLOCATE BY RISK CONTRIBUTION, NOT BY CAPITAL

Standard Markowitz: allocate Rs so that expected return is maximised.


Risk Parity: allocate so that every asset contributes EQUALLY to total risk.

Marginal Risk Contribution (MRC) of asset i:


MRC_i = w_i * (Sigma @ w)_i / portfolio_vol

Risk Parity: find weights w such that all MRC_i are equal.

RESULT: low-volatility assets get higher weights.


high-volatility assets get lower weights.
No need for expected return forecasts (which are unreliable).

USED BY: Bridgewater All Weather, AQR Risk Parity fund,


most pension funds for strategic asset allocation.

ADVANTAGE OVER MARKOWITZ:


Only needs covariance matrix (relatively stable).
Does NOT need expected returns (very unstable, huge estimation error).
Weights are diversified and stable across rebalancing periods.

Solution 2 — Black-Litterman
BLACK-LITTERMAN: BLEND MARKET EQUILIBRIUM WITH YOUR VIEWS

Step 1: Start from market equilibrium weights (e.g. NIFTY50 index weights)
These are the "neutral" weights that require no skill to justify.

Step 2: Express your views as quantitative statements:


"I believe TCS will outperform INFY by 3% over the next month"
"I expect RELIANCE to return 15% annualised"

Step 3: Black-Litterman blends equilibrium with views,

Quant Pro | Advanced Quant Finance Course | Week 10 — Elite Layer Page 12
QUANT PRO WEEK 10 | Days 71-78 | ELITE LAYER

Advanced Quant Finance Course Time Series | Cointegration | Microstructure | Execution | Final System

weighting by your confidence in each view.

RESULT: weights tilt AWAY from equilibrium only where you have conviction.
High confidence in a view -> larger tilt away from market weight.
No view -> stay at market weight (no uncompensated active risk).

PRACTICAL USE IN THIS COURSE:


Your ML model outputs a probability for each stock.
ML prob > 0.6 -> express a positive view on that stock.
Feed into Black-Litterman -> get optimal overweight positions.
This is how quant funds combine alpha signals with portfolio construction.

Python Code — Day 73: Risk Parity Portfolio


import pandas as pd, numpy as np
import [Link] as plt
from [Link] import minimize

symbols = ["TCS","INFY","RELIANCE","HDFCBANK","WIPRO"]
df = pd.read_csv("[Link]")
df["DATE1"] = pd.to_datetime(df["DATE1"])
df = df[df["SYMBOL"].isin(symbols)].sort_values(["SYMBOL","DATE1"])
df["Return"] = [Link]("SYMBOL")["CLOSE"].pct_change()
pivot = df.pivot_table(index="DATE1",columns="SYMBOL",values="Return").dropna()

mu = [Link]().values * 252 # annualised returns


cov = [Link]().values * 252 # annualised covariance
n = len(symbols)

# ■■ Markowitz Max Sharpe ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■


def neg_sharpe(w, mu, cov, rf=0.065):
r = w @ mu
v = [Link](w @ cov @ w)
return -(r - rf) / v if v > 0 else 0

cons = {"type":"eq","fun": lambda w: [Link]()-1}


bnds = [(0.01, 0.60)]*n
w0 = [Link](n)/n
mkw = minimize(neg_sharpe, w0, args=(mu,cov), method="SLSQP",
bounds=bnds, constraints=cons)
w_mkw = mkw.x

# ■■ Risk Parity ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■


def risk_parity_objective(w, cov):
port_var = w @ cov @ w
port_vol = [Link](port_var)
mrc = (cov @ w) / port_vol # marginal risk contributions
rc = w * mrc # risk contributions
# Minimise sum of squared differences from equal risk contribution
target_rc = port_vol / n
return [Link]((rc - target_rc)**2)

rp = minimize(risk_parity_objective, w0, args=(cov,),

Quant Pro | Advanced Quant Finance Course | Week 10 — Elite Layer Page 13
QUANT PRO WEEK 10 | Days 71-78 | ELITE LAYER

Advanced Quant Finance Course Time Series | Cointegration | Microstructure | Execution | Final System

method="SLSQP", bounds=bnds, constraints=cons)


w_rp = rp.x / [Link]()

# ■■ Equal weight ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■


w_eq = [Link](n)/n

# ■■ Performance comparison ■■■■■■■■■■■■■■■■■■■■■■■■■■■■


def port_metrics(w, mu, cov, rf=0.065):
r = w @ mu
v = [Link](w @ cov @ w)
return round(r*100,1), round(v*100,1), round((r-rf)/v,2)

print("=== PORTFOLIO METHOD COMPARISON ===")


print(f" {'Method':<20} {'Return%':>9} {'Vol%':>7} {'Sharpe':>8}")
print(" "+"-"*47)
for name, w in [("Markowitz MaxSR",w_mkw),("Risk Parity",w_rp),("Equal Weight",w_eq)]:
r,v,sr = port_metrics(w,mu,cov)
print(f" {name:<20} {r:>8.1f}% {v:>6.1f}% {sr:>8.2f}")

# ■■ Show risk contributions for Risk Parity ■■■■■■■■■■■


pv = [Link](w_rp @ cov @ w_rp)
mrc_rp = (cov @ w_rp) / pv
rc_rp = w_rp * mrc_rp / pv * 100
print("\nRisk Parity — Risk Contribution per Stock:")
for sym, rc in zip(symbols, rc_rp):
print(f" {sym:<12}: {rc:.1f}% (target: {100/n:.1f}%)")

# ■■ Weight comparison chart ■■■■■■■■■■■■■■■■■■■■■■■■■■■


x = [Link](n)
width = 0.25
fig, ax = [Link](figsize=(12,6))
[Link](x-width, w_mkw*100, width, label="Markowitz", color="tomato", alpha=0.85)
[Link](x, w_rp*100, width, label="Risk Parity",color="royalblue",alpha=0.85)
[Link](x+width, w_eq*100, width, label="Equal Wt", color="seagreen", alpha=0.85)
ax.set_xticks(x); ax.set_xticklabels(symbols)
ax.set_title("Portfolio Weights: Markowitz vs Risk Parity vs Equal Weight",fontweight="bold")
ax.set_ylabel("Weight (%)"); [Link](); [Link](True,alpha=0.2,axis="y")
plt.tight_layout()
[Link]("risk_parity_weights.png",dpi=150,bbox_inches="tight")
[Link]()

Day 73 Key Takeaways


• Markowitz weights are unstable — a 0.1% change in one expected return can move allocations by
20-30%.
• Risk parity only needs the covariance matrix — no expected return forecasts required, far more robust.
• Every stock contributes equally to portfolio volatility in risk parity — genuine diversification of risk.
• Black-Litterman is the bridge between risk parity (no views) and Markowitz (too many views) — use it
with ML signals.

Quant Pro | Advanced Quant Finance Course | Week 10 — Elite Layer Page 14
QUANT PRO WEEK 10 | Days 71-78 | ELITE LAYER

Advanced Quant Finance Course Time Series | Cointegration | Microstructure | Execution | Final System

• Always add min/max weight bounds (1% to 60%) in any optimisation — prevents degenerate
single-stock portfolios.

Quant Pro | Advanced Quant Finance Course | Week 10 — Elite Layer Page 15
QUANT PRO WEEK 10 | Days 71-78 | ELITE LAYER

Advanced Quant Finance Course Time Series | Cointegration | Microstructure | Execution | Final System

DAY

Market Microstructure

74 Inside the order book — adverse selection, Kyle Lambda, and the true cost of trading

What Microstructure Explains That Backtests Miss


Your backtest executes orders at the close price with a fixed slippage assumption. In reality, every trade
interacts with the limit order book in ways that depend on order size, stock liquidity, time of day, and
whether you are trading in the same direction as informed traders. Understanding these mechanics
explains why institutional strategies look perfect on paper but cost 30-50% more to execute in reality.

The Limit Order Book and Bid-Ask Spread


THE LIMIT ORDER BOOK — NIFTY FUTURES SNAPSHOT

SELL SIDE (Asks) BUY SIDE (Bids)


Price Qty Price Qty
22,510 50 <- best ask 22,505 80 <- best bid
22,515 120 22,500 200
22,520 200 22,495 350
22,530 400 22,490 500

Bid-ask spread = 22,510 - 22,505 = Rs 5


Midprice = (22,510 + 22,505) / 2 = 22,507.5

WHEN YOU BUY AT MARKET:


- Your order hits the best ask: Rs 22,510
- You paid Rs 2.50 above midprice = half the spread
- For 50 lots (1 lot = 50 units): immediate cost = 50*50*2.50 = Rs 6,250

THREE COMPONENTS OF THE SPREAD:

1. ORDER PROCESSING COST (10-15%)


Pure technology and operational cost of running the exchange.

2. INVENTORY RISK (35-45%)


Market makers hold positions against their will.
If they bought from you at 22,510, price might keep falling.
Spread compensates for this directional risk.

3. ADVERSE SELECTION (40-50%)


The single most important component.
The person on the other side of your trade may know something you do not.
If you are buying, the seller might know bad news is coming.
Spread compensates market makers for trading with informed traders.

Quant Pro | Advanced Quant Finance Course | Week 10 — Elite Layer Page 16
QUANT PRO WEEK 10 | Days 71-78 | ELITE LAYER

Advanced Quant Finance Course Time Series | Cointegration | Microstructure | Execution | Final System

Adverse Selection — Why This Matters for Your Strategy


Adverse selection is the hidden cost that no backtest captures. When your strategy sends a buy order, the
market maker who fills it has to ask: is this order from an informed trader who knows the price is going up?
If yes, the market maker is selling at a loss. To protect themselves, market makers widen the spread when
they sense informed order flow. This is why illiquid stocks with thin order books have enormous spreads —
market makers there face more adverse selection risk.

Python Code — Day 74: Amihud Illiquidity Ratio


import pandas as pd, numpy as np
import [Link] as plt

# Amihud (2002) illiquidity ratio: best proxy for price impact


# when tick-level order book data is unavailable
# Illiquidity_t = |Return_t| / Volume_Rs_t
# Higher = less liquid = your order moves price more per rupee of trading

df = pd.read_csv("[Link]")
df["DATE1"] = pd.to_datetime(df["DATE1"])
symbols = ["TCS","INFY","RELIANCE","HDFCBANK","WIPRO"]
df = df[df["SYMBOL"].isin(symbols)].sort_values(["SYMBOL","DATE1"]).copy()

df["Return_abs"] = [Link]("SYMBOL")["CLOSE"].pct_change().abs()
df["Volume_Rs_Cr"] = df["CLOSE"] * df["TOTTRDQTY"] / 1e7 # in crore

# Amihud ratio per day (avoid division by zero)


df["Amihud"] = df["Return_abs"] / df["Volume_Rs_Cr"].replace(0, [Link])

# 20-day rolling average (smooth out outliers)


df["Amihud_20d"] = [Link]("SYMBOL")["Amihud"].transform(
lambda x: [Link](20).mean())

# Annual summary
summary = ([Link]("SYMBOL")["Amihud_20d"]
.mean()
.sort_values(ascending=False)
.reset_index())
[Link] = ["Symbol","Avg_Amihud"]

print("=== AMIHUD ILLIQUIDITY RANKING ===")


print("Higher score = less liquid = your orders move price more")
print()
for _, row in [Link]():
tag = "AVOID for large orders" if row["Avg_Amihud"] > summary["Avg_Amihud"].median() else "OK for
medium orders"
print(f" {row['Symbol']:<12}: {row['Avg_Amihud']:.2e} {tag}")

# Plot rolling Amihud for all 5 stocks


fig, ax = [Link](figsize=(13,6))
for sym in symbols:
sdf = df[df["SYMBOL"]==sym].set_index("DATE1")
[Link]([Link], sdf["Amihud_20d"]*1e4, lw=1.5, label=sym)
ax.set_title("Amihud Illiquidity Ratio x 10^4 — 20-Day Rolling Average",fontweight="bold")

Quant Pro | Advanced Quant Finance Course | Week 10 — Elite Layer Page 17
QUANT PRO WEEK 10 | Days 71-78 | ELITE LAYER

Advanced Quant Finance Course Time Series | Cointegration | Microstructure | Execution | Final System

ax.set_ylabel("Illiquidity (|Return| / Volume in Rs Cr)")


[Link](); [Link](True,alpha=0.2)
plt.tight_layout()
[Link]("amihud_illiquidity.png",dpi=150,bbox_inches="tight")
[Link]()

print("\nKyle Lambda (conceptual):")


print("Lambda = price impact per unit of net order flow (Rs)")
print("Compute from tick data: regress price change on signed volume")
print("Higher lambda = more price impact = worse execution for large orders")
print("Practical rule: trade < 1% of daily volume to stay below market impact")

Day 74 Key Takeaways


• Adverse selection is the largest component of the bid-ask spread — market makers charge extra for
trading with informed traders.
• Amihud illiquidity ratio is the best proxy for market impact when order-level data is unavailable.
• Never trade more than 1% of a stock's daily average volume with market orders — your impact becomes
the dominant cost.
• NIFTY futures and large-cap stocks are highly liquid — NSE small-caps can have 10x the Amihud ratio
of large-caps.
• Kyle Lambda from tick data gives the most precise market impact estimate — available from NSE tick
data subscription.

Quant Pro | Advanced Quant Finance Course | Week 10 — Elite Layer Page 18
QUANT PRO WEEK 10 | Days 71-78 | ELITE LAYER

Advanced Quant Finance Course Time Series | Cointegration | Microstructure | Execution | Final System

DAY
Execution Algorithms — TWAP, VWAP, and Implementation
Shortfall

75 How institutional desks minimise the cost of executing large orders

Why Large Orders Need Algorithms


If you buy 50,000 shares of TCS with a single market order, your order will walk up the order book — buying
the 200 shares at Rs 3510, then the 400 at Rs 3515, then the 800 at Rs 3520, and so on. By the time you
are done, you have moved the price against yourself. The total cost above midprice can be 0.3-0.8% on a
large order. For a Rs 1 crore order, that is Rs 30,000-80,000 in pure execution drag on top of STT and
brokerage. Execution algorithms solve this.

TWAP, VWAP, and Implementation Shortfall


TWAP — TIME WEIGHTED AVERAGE PRICE
Divide total order into equal slices. Execute one slice every N minutes.
Goal: achieve the time-weighted average price of the day.
Pro: Simple, predictable, easy to explain to compliance.
Con: Ignores volume — executes the same size during quiet and active periods.
Use when: you have no alpha decay (signal is not time-sensitive)
and you want simplicity over optimality.

VWAP — VOLUME WEIGHTED AVERAGE PRICE


Execute proportionally to the market volume profile throughout the day.
More shares in high-volume periods (open, close). Less at midday.
Goal: beat or match the day's VWAP — the institutional benchmark.
Pro: Minimises market impact by hiding in natural volume.
Con: Requires volume forecast. Predictable — can be front-run.
Use when: executing large equity orders for long-term positions.

TYPICAL NSE INTRADAY VOLUME PROFILE (% of daily volume per hour):


09:15-10:00 22% <- OPEN: very high volume, large spreads
10:00-11:00 14%
11:00-12:00 10%
12:00-13:00 9% <- MIDDAY: lowest volume
13:00-14:00 10%
14:00-15:00 14%
15:00-15:30 21% <- CLOSE: very high volume again

IMPLEMENTATION SHORTFALL (IS)


The most academically correct execution metric.
IS = (Actual average execution price - Decision price) x Total shares
Decision price = midprice when the trading DECISION was made.

Quant Pro | Advanced Quant Finance Course | Week 10 — Elite Layer Page 19
QUANT PRO WEEK 10 | Days 71-78 | ELITE LAYER

Advanced Quant Finance Course Time Series | Cointegration | Microstructure | Execution | Final System

IS captures: timing cost + market impact + opportunity cost.


Almgren-Chriss model minimises IS by optimally spreading execution
across time, trading off urgency vs market impact mathematically.

Python Code — Day 75: VWAP Execution Schedule Builder


import numpy as np, pandas as pd
import [Link] as plt

# ■■ Simulate NSE intraday volume profile ■■■■■■■■■■■■■


# Based on typical NSE large-cap stock volume distribution
[Link](42)

time_slots = [
"09:15","09:30","09:45","10:00","10:15","10:30","10:45","11:00",
"11:15","11:30","11:45","12:00","12:15","12:30","12:45","13:00",
"13:15","13:30","13:45","14:00","14:15","14:30","14:45","15:00",
"15:15"
]
n_slots = len(time_slots)

# U-shaped volume profile (realistic NSE intraday)


base_vol = [Link]([
9.0, 5.0, 3.5, 3.0, 2.5, 2.5, 2.5, 2.5, # 09:15 - 11:00
2.2, 2.2, 2.0, 2.0, 2.0, 2.0, 2.2, 2.2, # 11:00 - 13:00
2.5, 2.5, 2.8, 3.0, 3.5, 4.5, 5.5, 8.0, # 13:00 - 15:00
9.5 # 15:15 close
])
vol_profile = base_vol / base_vol.sum() # normalise

# Add intraday randomness


actual_vol = vol_profile * (0.75 + 0.5*[Link](n_slots))
actual_vol = actual_vol / actual_vol.sum()

# ■■ Simulate intraday price path ■■■■■■■■■■■■■■■■■■■■■


price_path = [3500.0]
for _ in range(n_slots - 1):
price_path.append(price_path[-1] * (1 + [Link](0, 0.0015)))

# ■■ TWAP schedule ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■


total_order = 10_000 # shares to execute
twap_slices = [Link](n_slots, total_order // n_slots)
twap_slices[-1] += total_order - twap_slices.sum() # remainder to last slot

# ■■ VWAP schedule ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■


vwap_slices = [Link](vol_profile * total_order).astype(int)
vwap_slices[-1] += total_order - vwap_slices.sum()

# ■■ Execution price calculation ■■■■■■■■■■■■■■■■■■■■■■■


def avg_exec_price(slices, prices):
total = sum(slices)
return sum(s*p for s,p in zip(slices,prices)) / total

twap_exec = avg_exec_price(twap_slices, price_path)

Quant Pro | Advanced Quant Finance Course | Week 10 — Elite Layer Page 20
QUANT PRO WEEK 10 | Days 71-78 | ELITE LAYER

Advanced Quant Finance Course Time Series | Cointegration | Microstructure | Execution | Final System

vwap_exec = avg_exec_price(vwap_slices, price_path)


mkt_vwap = avg_exec_price([Link](actual_vol*total_order).astype(int), price_path)

print("=== EXECUTION ANALYSIS ===")


print(f"Market VWAP (benchmark): Rs {mkt_vwap:.2f}")
print(f"TWAP execution : Rs {twap_exec:.2f} | vs VWAP: {twap_exec-mkt_vwap:+.2f}")
print(f"VWAP execution : Rs {vwap_exec:.2f} | vs VWAP: {vwap_exec-mkt_vwap:+.2f}")

# Implementation Shortfall
decision_price = price_path[0] # price when you decided to trade
is_twap = (twap_exec - decision_price) * total_order
is_vwap = (vwap_exec - decision_price) * total_order
print(f"\nImplementation Shortfall (IS):")
print(f" TWAP IS: Rs {is_twap:+,.0f} ({(twap_exec/decision_price-1)*100:+.3f}%)")
print(f" VWAP IS: Rs {is_vwap:+,.0f} ({(vwap_exec/decision_price-1)*100:+.3f}%)")

# ■■ Plot ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
fig, axes = [Link](2, 1, figsize=(13,8), sharex=True)

x = range(n_slots)
axes[0].bar(x, twap_slices, alpha=0.7, label="TWAP (equal)", color="royalblue", width=0.4)
axes[0].bar([i+0.4 for i in x], vwap_slices, alpha=0.7, label="VWAP (vol-weighted)",
color="seagreen", width=0.4)
axes[0].plot(x, vol_profile*total_order, "o--", color="tomato", lw=2,
ms=4, label="Market vol profile")
axes[0].set_title("Execution Schedule: TWAP vs VWAP vs Market Volume", fontweight="bold")
axes[0].set_ylabel("Shares to Execute")
axes[0].legend(fontsize=8); axes[0].grid(True, alpha=0.2)

axes[1].plot(x, price_path, color="royalblue", lw=2, label="Price")


axes[1].axhline(twap_exec, color="orange", lw=1.5, linestyle="--",
label=f"TWAP avg: Rs{twap_exec:.1f}")
axes[1].axhline(vwap_exec, color="seagreen",lw=1.5, linestyle="--",
label=f"VWAP avg: Rs{vwap_exec:.1f}")
axes[1].axhline(mkt_vwap, color="tomato", lw=2,
label=f"Market VWAP: Rs{mkt_vwap:.1f}")
axes[1].set_title("Intraday Price and Execution Benchmarks", fontweight="bold")
axes[1].set_ylabel("Price (Rs)"); axes[1].legend(fontsize=8)
axes[1].grid(True, alpha=0.2)
axes[1].set_xticks(range(0,n_slots,4))
axes[1].set_xticklabels([time_slots[i] for i in range(0,n_slots,4)], rotation=30)

[Link]("VWAP Execution Algorithm — 10,000 Share Order", fontweight="bold")


plt.tight_layout()
[Link]("vwap_execution.png", dpi=150, bbox_inches="tight")
[Link]()

Day 75 Key Takeaways


• NSE volume is U-shaped: very high at 9:15-10:00 open and 15:00-15:30 close — VWAP must match
this profile.

Quant Pro | Advanced Quant Finance Course | Week 10 — Elite Layer Page 21
QUANT PRO WEEK 10 | Days 71-78 | ELITE LAYER

Advanced Quant Finance Course Time Series | Cointegration | Microstructure | Execution | Final System

• VWAP execution beats TWAP when the volume forecast is accurate — it hides your order in natural
market volume.
• Implementation Shortfall captures the full cost from decision to execution — the most complete
execution quality metric.
• For orders below 0.1% of daily volume (most retail algo trading): simple market orders near close are
fine.
• Almgren-Chriss provides the mathematically optimal execution schedule — study it if you join an
institutional desk.

Quant Pro | Advanced Quant Finance Course | Week 10 — Elite Layer Page 22
QUANT PRO WEEK 10 | Days 71-78 | ELITE LAYER

Advanced Quant Finance Course Time Series | Cointegration | Microstructure | Execution | Final System

DAY
Code Architecture + SQL Mastery

76 Refactor notebooks to production packages — then master the database language every quant desk
uses

Part 1: Code Architecture — Before and After


The difference between a student project and a professional tool is not the strategy — it is the code quality.
A recruiter reading your GitHub for 60 seconds will form an impression from variable names, function
structure, and documentation before reading a single line of logic. This section shows the exact
transformation from notebook-quality code to production-quality code.

BEFORE (notebook style): AFTER (production style):

x = df["C"].pct_change() def calculate_daily_returns(


y = [Link]()*252**0.5 prices: [Link],
z = [Link]()/[Link]()*252**0.5 trading_days: int = 252
print(z) ) -> [Link]:
"""
Calculate daily returns and
annualised risk metrics.

Args:
prices: closing prices
trading_days: days per year

Returns:
DataFrame with ret, vol, sharpe
"""
ret = prices.pct_change().dropna()
vol = [Link]() * trading_days**0.5
sharpe = [Link]()/[Link]()*trading_days**0.5
return [Link]({
"daily_ret":ret,"ann_vol":vol,
"sharpe":sharpe})

Part 2: SQL Mastery — The Complete Quant Guide


Every professional quant environment uses relational databases. NSE tick data, fundamental data, option
chain history — all of it lives in SQL databases, not CSV files. SQL lets you query millions of rows in
milliseconds, join tables across datasets, and run rolling calculations that would take Pandas minutes. This
section is the complete SQL guide that belongs in this course.

Python Code — Day 76: Complete SQL Guide for Quants

Quant Pro | Advanced Quant Finance Course | Week 10 — Elite Layer Page 23
QUANT PRO WEEK 10 | Days 71-78 | ELITE LAYER

Advanced Quant Finance Course Time Series | Cointegration | Microstructure | Execution | Final System

# ■■ SETUP: Create a stock price database ■■■■■■■■■■■■


import sqlite3, pandas as pd, numpy as np
from sqlalchemy import create_engine

# Create SQLite database (replace with PostgreSQL in production)


conn = [Link]("[Link]")
engine = create_engine("sqlite:///[Link]")

# Create tables
[Link]("""
CREATE TABLE IF NOT EXISTS prices (
id INTEGER PRIMARY KEY AUTOINCREMENT,
symbol TEXT NOT NULL,
date TEXT NOT NULL,
open REAL, high REAL, low REAL, close REAL,
volume INTEGER,
UNIQUE(symbol, date)
);
CREATE TABLE IF NOT EXISTS signals (
id INTEGER PRIMARY KEY AUTOINCREMENT,
symbol TEXT NOT NULL,
date TEXT NOT NULL,
signal TEXT,
rsi REAL,
adx REAL,
UNIQUE(symbol, date)
);
CREATE INDEX IF NOT EXISTS idx_prices_sym ON prices(symbol);
CREATE INDEX IF NOT EXISTS idx_prices_date ON prices(date);
""")

# Load Bhavcopy data into the database


df = pd.read_csv("[Link]")
[Link] = [Link]().[Link]()
df_db = df[df["SERIES"]=="EQ"][["SYMBOL","DATE1","OPEN","HIGH","LOW","CLOSE","TOTTRDQTY"]].copy()
df_db.columns = ["symbol","date","open","high","low","close","volume"]
df_db.to_sql("prices", engine, if_exists="append", index=False)
print(f"Loaded {len(df_db)} rows into prices table")

# ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
# SQL QUERY 1: Basic SELECT with filters
# ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
q1 = """
SELECT symbol, date, close
FROM prices
WHERE symbol = 'TCS'
AND date >= '2023-01-01'
ORDER BY date DESC
LIMIT 10
"""

Quant Pro | Advanced Quant Finance Course | Week 10 — Elite Layer Page 24
QUANT PRO WEEK 10 | Days 71-78 | ELITE LAYER

Advanced Quant Finance Course Time Series | Cointegration | Microstructure | Execution | Final System

print("\n=== Q1: Recent TCS prices ===")


print(pd.read_sql(q1, conn).to_string(index=False))

# ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
# SQL QUERY 2: GROUP BY aggregation
# ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
q2 = """
SELECT
symbol,
COUNT(*) AS trading_days,
ROUND(AVG(close), 2) AS avg_close,
ROUND(MAX(close), 2) AS max_close,
ROUND(MIN(close), 2) AS min_close,
ROUND(AVG(volume) / 1000000, 2) AS avg_vol_M
FROM prices
GROUP BY symbol
ORDER BY avg_vol_M DESC
"""
print("\n=== Q2: Summary stats per stock ===")
print(pd.read_sql(q2, conn).to_string(index=False))

# ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
# SQL QUERY 3: Window function — 20-day moving average
# ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
q3 = """
SELECT
symbol,
date,
close,
ROUND(AVG(close) OVER (
PARTITION BY symbol
ORDER BY date
ROWS BETWEEN 19 PRECEDING AND CURRENT ROW
), 2) AS sma_20
FROM prices
WHERE symbol = 'TCS'
ORDER BY date DESC
LIMIT 10
"""
print("\n=== Q3: 20-day SMA using SQL window function ===")
print(pd.read_sql(q3, conn).to_string(index=False))

# ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
# SQL QUERY 4: Daily return using LAG window function
# ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
q4 = """
SELECT
symbol,
date,

Quant Pro | Advanced Quant Finance Course | Week 10 — Elite Layer Page 25
QUANT PRO WEEK 10 | Days 71-78 | ELITE LAYER

Advanced Quant Finance Course Time Series | Cointegration | Microstructure | Execution | Final System

close,
ROUND(
(close - LAG(close) OVER (PARTITION BY symbol ORDER BY date))
/ LAG(close) OVER (PARTITION BY symbol ORDER BY date) * 100
, 3) AS daily_ret_pct
FROM prices
WHERE symbol IN ('TCS', 'INFY')
ORDER BY symbol, date DESC
LIMIT 20
"""
print("\n=== Q4: Daily returns with LAG ===")
print(pd.read_sql(q4, conn).to_string(index=False))

# ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
# SQL QUERY 5: Top gainers each month
# ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
q5 = """
WITH monthly AS (
SELECT
symbol,
SUBSTR(date, 1, 7) AS month,
MIN(close) AS close_start,
MAX(close) AS close_end,
ROUND((MAX(close)-MIN(close))/MIN(close)*100, 2) AS approx_return_pct
FROM prices
GROUP BY symbol, SUBSTR(date,1,7)
)
SELECT symbol, month, close_start, close_end, approx_return_pct
FROM monthly
ORDER BY month DESC, approx_return_pct DESC
"""
df_monthly = pd.read_sql(q5, conn)
print("\n=== Q5: Monthly return by stock (top rows) ===")
print(df_monthly.head(15).to_string(index=False))

# ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
# SQL QUERY 6: JOIN prices with signals table
# ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
# First insert some dummy signals
sig_rows = [('TCS','2023-06-01','BUY',28.5,32.1),
('INFY','2023-06-01','HOLD',55.2,18.4)]
[Link]("INSERT OR IGNORE INTO signals(symbol,date,signal,rsi,adx) VALUES(?,?,?,?,?)",
sig_rows)
[Link]()

q6 = """
SELECT
[Link],
[Link],

Quant Pro | Advanced Quant Finance Course | Week 10 — Elite Layer Page 26
QUANT PRO WEEK 10 | Days 71-78 | ELITE LAYER

Advanced Quant Finance Course Time Series | Cointegration | Microstructure | Execution | Final System

[Link],
[Link],
[Link],
[Link]
FROM prices p
JOIN signals s ON [Link] = [Link]
AND [Link] = [Link]
ORDER BY [Link] DESC
"""
print("\n=== Q6: Prices joined with signals ===")
print(pd.read_sql(q6, conn).to_string(index=False))

# ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
# PANDAS BRIDGE: read any SQL query directly into DataFrame
# ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
tcs_df = pd.read_sql(
"SELECT date, close FROM prices WHERE symbol='TCS' ORDER BY date",
con=conn,
parse_dates=["date"]
)
tcs_df["sma_20"] = tcs_df["close"].rolling(20).mean()
print(f"\nSQLAlchemy bridge: {len(tcs_df)} TCS rows loaded into DataFrame")
print("Continue using Pandas for all calculations after loading from SQL")

[Link]()
print("\nSQL Mastery complete. In production: replace sqlite:///[Link]")
print("with postgresql://user:password@host:5432/dbname")

SQL Quick Reference — All Commands You Need


SQL Command What It Does Pandas Equivalent

SELECT col FROM tbl WHERE cond Filter and select columns df[condition][columns]

GROUP BY sym ORDER BY col DESC Aggregate per stock, sort [Link]("sym").agg(...).sort_
values(...)

LIMIT N Return only first N rows [Link](N) or [Link](N,col)

JOIN ... ON key1=key2 Merge two tables on matching key [Link](df2, on="key")

AVG(col) OVER (PARTITION BY sym 20-day moving average in SQL [Link]("sym")["col"].rolling


ORDER BY date ROWS 19 PRECEDING) (20).mean()

LAG(col) OVER (PARTITION BY sym Previous row value per group [Link]("sym")["col"].shift(1
ORDER BY date) )

WITH monthly AS (SELECT ...) Common Table Expression (CTE) Assign result to variable then
reuse

pd.read_sql(query, con=engine) SQL query directly to DataFrame The SQLAlchemy bridge — use this
always

Quant Pro | Advanced Quant Finance Course | Week 10 — Elite Layer Page 27
QUANT PRO WEEK 10 | Days 71-78 | ELITE LAYER

Advanced Quant Finance Course Time Series | Cointegration | Microstructure | Execution | Final System

Day 76 Key Takeaways


• Type hints (def f(x: [Link]) -> float:) make functions self-documenting and catch type errors early.
• Window functions (AVG OVER, LAG OVER) compute rolling metrics entirely in SQL — no Python loop
needed.
• CTE (WITH clause) lets you build complex multi-step queries that are readable and maintainable.
• Always index on symbol and date columns — queries without indexes on large tables take 100x longer.
• pd.read_sql() with SQLAlchemy is the bridge: query in SQL, analyse in Pandas — best of both worlds.

Quant Pro | Advanced Quant Finance Course | Week 10 — Elite Layer Page 28
QUANT PRO WEEK 10 | Days 71-78 | ELITE LAYER

Advanced Quant Finance Course Time Series | Cointegration | Microstructure | Execution | Final System

DAY

Final Project Part 1 — Complete Modular System

77 Connect all 10 weeks into one tested, documented, live-running system

What the Final System Looks Like


Today you wire together every component built across all 10 weeks: live data from yfinance, signals from
SMA + ADX strategy, GARCH vol forecast, VaR calculation, Kelly position sizing, SQL storage, daily JSON
output, Telegram alert, and the automated tearsheet. Every piece has been built independently. Today it
becomes one coherent system that runs daily at 4 PM automatically.

Python Code — Day 77: Complete [Link] Integration


#!/usr/bin/env python3
"""
Quant Pro — Complete Trading System
Runs daily at 16:05. Downloads data, generates signals,
computes risk, logs everything, sends alerts.
"""
import os, sys, logging, json, warnings
from datetime import datetime, date
from typing import Dict

import pandas as pd
import numpy as np
import yfinance as yf
from arch import arch_model
from scipy import stats
from sqlalchemy import create_engine

[Link]("ignore")

# ■■ CONFIG ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
SYMBOLS = ["[Link]","[Link]","[Link]","[Link]","[Link]"]
NAMES = [[Link](".NS","") for s in SYMBOLS]
CAPITAL = 500_000
FAST_SMA = 20
SLOW_SMA = 50
ADX_THRESH = 25
KELLY_FRACTION = 0.25
VAR_CONF = 0.95
ROUND_TRIP_COST = 0.0023
TELEGRAM_TOKEN = [Link]("TELEGRAM_TOKEN","")
TELEGRAM_CHAT = [Link]("TELEGRAM_CHAT_ID","")
DB_PATH = [Link]("~/quant_system/[Link]")
LOG_PATH = [Link]("~/quant_system/logs/")

Quant Pro | Advanced Quant Finance Course | Week 10 — Elite Layer Page 29
QUANT PRO WEEK 10 | Days 71-78 | ELITE LAYER

Advanced Quant Finance Course Time Series | Cointegration | Microstructure | Execution | Final System

OUT_PATH = [Link]("~/quant_system/outputs/")

for p in [LOG_PATH, OUT_PATH, [Link](DB_PATH)]:


[Link](p, exist_ok=True)

# ■■ LOGGING ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
[Link](
level=[Link],
format="%(asctime)s %(levelname)s %(message)s",
handlers=[
[Link](f"{LOG_PATH}{[Link]()}.log"),
[Link]([Link])
]
)
log = [Link]()

# ■■ HELPERS ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
def _rsi(s: [Link], p: int = 14) -> [Link]:
d=[Link](); g=[Link](lower=0).ewm(com=p-1,min_periods=p).mean()
return 100-100/(1+g/(-d).clip(lower=0).ewm(com=p-1,min_periods=p).mean())

def _adx(df: [Link], p: int = 14) -> [Link]:


h,l,c=df["High"],df["Low"],df["Close"]
tr=[Link]([h-l,([Link]()).abs(),([Link]()).abs()],axis=1).max(1)
up=[Link](); dn=[Link]()-l
pm=[Link]((up>dn)&(up>0),up,0); mm=[Link]((dn>up)&(dn>0),dn,0)
atr=[Link](tr).ewm(alpha=1/p,adjust=False).mean()
pd_=100*[Link](pm).ewm(alpha=1/p,adjust=False).mean()/atr
md_=100*[Link](mm).ewm(alpha=1/p,adjust=False).mean()/atr
return (100*(pd_-md_).abs()/(pd_+md_)).ewm(alpha=1/p,adjust=False).mean()

def send_telegram(msg: str) -> None:


if not TELEGRAM_TOKEN: return
try:
import [Link]
url = f"[Link]
data = [Link]({"chat_id":TELEGRAM_CHAT,"text":msg}).encode()
[Link](
[Link](url,data,{"Content-Type":"application/json"}),
timeout=10)
except Exception as e:
[Link](f"Telegram: {e}")

# ■■ MODULE 1: DATA ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■


def download_data() -> Dict[str,[Link]]:
data = {}
for sym, name in zip(SYMBOLS, NAMES):
try:
df = [Link](sym).history(period="2y")
[Link] = pd.to_datetime([Link]).tz_localize(None)
data[name] = df.sort_index()
[Link](f" Downloaded {name}: {len(df)} rows")

Quant Pro | Advanced Quant Finance Course | Week 10 — Elite Layer Page 30
QUANT PRO WEEK 10 | Days 71-78 | ELITE LAYER

Advanced Quant Finance Course Time Series | Cointegration | Microstructure | Execution | Final System

except Exception as e:
[Link](f" Failed {name}: {e}")
return data

# ■■ MODULE 2: SIGNALS ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■


def generate_signals(data: Dict) -> Dict:
signals = {}
for name, df in [Link]():
try:
c = df["Close"]
sma_f = [Link](FAST_SMA).mean()
sma_s = [Link](SLOW_SMA).mean()
rsi = _rsi(c)
adx = _adx(df)
t,p = [Link][-1], [Link][-2]
trend = float([Link][-1]) > ADX_THRESH
golden = float(sma_f.iloc[-2])<=float(sma_s.iloc[-2]) and
float(sma_f.iloc[-1])>float(sma_s.iloc[-1])
death = float(sma_f.iloc[-2])>=float(sma_s.iloc[-2]) and
float(sma_f.iloc[-1])<float(sma_s.iloc[-1])
if golden and trend: sig = "BUY"
elif death and trend: sig = "SELL"
else: sig = "HOLD"
signals[name] = {"signal":sig,"price":round(float(t["Close"]),2),
"rsi":round(float([Link][-1]),1),
"adx":round(float([Link][-1]),1),"trend":trend}
except Exception as e:
[Link](f" Signal {name}: {e}")
return signals

# ■■ MODULE 3: RISK ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■


def compute_risk(data: Dict) -> Dict:
pivot = [Link]({n:d["Close"].pct_change() for n,d in [Link]()}).dropna()
w = [Link](len(data))/len(data)
pret = [Link] @ w
var95 = [Link](pret, 5)
cvar95= pret[pret<=var95].mean()
try:
gm = arch_model(pret*100,vol="Garch",p=1,q=1,mean="Zero",dist="t")
gr = [Link](disp="off")
gvol=float([Link]([Link](horizon=1).[Link][-1,0]))
except:
gvol=float([Link](pret).rolling(20).std().iloc[-1]*100)
return {"var95_pct":round(var95*100,3),"var95_rs":round(abs(var95)*CAPITAL,0),
"cvar95_pct":round(cvar95*100,3),"garch_vol_pct":round(gvol,3)}

# ■■ MODULE 4: POSITION SIZING ■■■■■■■■■■■■■■■■■■■■■■■■


def size_positions(signals: Dict, risk: Dict) -> Dict:
vol_daily = abs(risk["var95_pct"]) / 1.645 # back out sigma from VaR
sizes = {}

Quant Pro | Advanced Quant Finance Course | Week 10 — Elite Layer Page 31
QUANT PRO WEEK 10 | Days 71-78 | ELITE LAYER

Advanced Quant Finance Course Time Series | Cointegration | Microstructure | Execution | Final System

for name, s in [Link]():


if s["signal"] == "BUY":
# Volatility targeting: size so daily risk = 1.5% of capital
target_risk_rs = CAPITAL * 0.015
pos_rs = target_risk_rs / (vol_daily/100) if vol_daily>0 else 0
pos_rs = min(pos_rs, CAPITAL * 0.20) * KELLY_FRACTION
shares = max(1, int(pos_rs / s["price"]))
sizes[name] = {"shares":shares,"value":round(shares*s["price"],0)}
return sizes

# ■■ MODULE 5: STORE TO SQL ■■■■■■■■■■■■■■■■■■■■■■■■■■■


def store_to_db(data: Dict, signals: Dict) -> None:
try:
engine = create_engine(f"sqlite:///{DB_PATH}")
for name, df in [Link]():
df_db = df[["Open","High","Low","Close","Volume"]].copy()
df_db.columns = ["open","high","low","close","volume"]
df_db["symbol"] = name
df_db["date"] = df_db.[Link](str)
df_db.to_sql("prices", engine, if_exists="append",
index=False, method="multi")
[Link](f" Stored to DB: {DB_PATH}")
except Exception as e:
[Link](f" DB store failed: {e}")

# ■■ MODULE 6: DASHBOARD + ALERTS ■■■■■■■■■■■■■■■■■■■■■


def print_dashboard(signals: Dict, risk: Dict, sizes: Dict) -> None:
print(f"\n{'='*60}")
print(f" QUANT PRO DASHBOARD {[Link]()}")
print(f"{'='*60}")
print(f" RISK: VaR(95%)={risk['var95_pct']:.2f}% ",
f"CVaR={risk['cvar95_pct']:.2f}%",
f"GARCH={risk['garch_vol_pct']:.2f}%/day")
print(f" {'■'*56}")
print(f" {'Stock':<14}{'Price':>8}{'RSI':>6}{'ADX':>6} {'Signal':<7}{'Size'}")
print(f" {'■'*56}")
alerts = []
for name, s in [Link]():
sz = [Link](name,{})
tag = f"{[Link]('shares','-')} sh" if sz else ""
mkr = ">> " if s["signal"]!="HOLD" else " "
print(f" {mkr}{name:<11}{s['price']:>9.0f}{s['rsi']:>6.1f}{s['adx']:>6.1f} {s['signal']:<7}{tag}")
if s["signal"] != "HOLD":
[Link](f"{s['signal']} {name} @ Rs{s['price']:.0f}")
if alerts:
print(f"\n {len(alerts)} SIGNAL(S): {' |'.join(alerts)}")
send_telegram(f"QUANT PRO {[Link]()}\n"+'\n'.join(alerts))
print(f"{'='*60}\n")

Quant Pro | Advanced Quant Finance Course | Week 10 — Elite Layer Page 32
QUANT PRO WEEK 10 | Days 71-78 | ELITE LAYER

Advanced Quant Finance Course Time Series | Cointegration | Microstructure | Execution | Final System

# ■■ MAIN DAILY JOB ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■


def run():
[Link](f"Pipeline start: {[Link]()}")
data = download_data()
signals = generate_signals(data)
risk = compute_risk(data)
sizes = size_positions(signals, risk)
store_to_db(data, signals)
print_dashboard(signals, risk, sizes)
[Link]({"date":str([Link]()),"signals":signals,
"risk":risk,"sizes":sizes},
open(f"{OUT_PATH}output_{[Link]()}.json","w"),indent=2)
[Link](f"Pipeline complete: {[Link]()}")

if __name__ == "__main__":
run()

Day 77 Key Takeaways


• The [Link] orchestrator imports from all modules and runs them in sequence — no module imports
from another module.
• Every function has a type hint and handles its own exceptions — the pipeline never crashes because
one stock failed.
• SQL storage via SQLAlchemy creates a permanent historical log — you can query any past signal years
later.
• Position sizing uses volatility targeting (not fixed Rs) — position shrinks automatically when the market
becomes wild.
• JSON output gives a human-readable daily record — your audit trail for every signal the system has ever
fired.

Quant Pro | Advanced Quant Finance Course | Week 10 — Elite Layer Page 33
QUANT PRO WEEK 10 | Days 71-78 | ELITE LAYER

Advanced Quant Finance Course Time Series | Cointegration | Microstructure | Execution | Final System

DAY Final Project Part 2 — GitHub Polish + Maximum Output


Guide

78 Course completion, GitHub portfolio, and everything you need to get the most from this entire 10-week
journey

Part 1: GitHub Portfolio — The Document That Gets You Hired


Your GitHub repository is now your professional CV in the quant world. Hedge fund recruiters, prop desk
hiring managers, and WorldQuant research managers actively search GitHub. The README they see in 60
seconds will determine whether they click further or move on. Here is the exact standard that separates
profiles that get calls from profiles that do not.

WINNING GITHUB README STRUCTURE

# Quant Pro — Complete Algorithmic Trading System


*10-week advanced course | Python | NSE live data | AWS deployed*

## System Overview (3 sentences maximum)


"A complete modular quantitative trading system that downloads live NSE
market data daily, generates signals using SMA+ADX+ML ensemble, computes
GARCH volatility and Kelly-sized positions, stores everything in SQLite,
and sends Telegram alerts. Deployed on AWS EC2, running at 4 PM IST daily."

## Performance (OUT-OF-SAMPLE ONLY — never hide this)


| Strategy | OOS Return | Sharpe | Calmar | MaxDD |
|-------------------|-----------|--------|--------|---------|
| SMA+ADX Crossover | +9.1% | 1.05 | 0.77 | -11.8% |
| Iron Condor VRP | +18.3% | 1.41 | 1.10 | -16.6% |
| ML Direction | AUC 0.57 | -- | -- | -- |
* All returns net of STT, slippage, and spread costs

## Architecture Diagram
[paste ASCII or image diagram here]

## Models and Tools Built


- Black-Scholes pricer + full Greeks (Delta, Gamma, Theta, Vega)
- Monte Carlo GBM simulation + VaR calculation
- GARCH(1,1) dynamic volatility forecast
- ML alpha pipeline (GBM, TimeSeriesSplit, SHAP interpretability)
- Risk parity portfolio optimisation
- Kalman Filter dynamic hedge ratio for pairs trading
- VWAP/TWAP execution schedule builder
- SQL stock database (SQLite -> PostgreSQL in production)
- Professional strategy tearsheet generator
- Live cloud deployment on AWS EC2 with cron + Telegram alerts

Quant Pro | Advanced Quant Finance Course | Week 10 — Elite Layer Page 34
QUANT PRO WEEK 10 | Days 71-78 | ELITE LAYER

Advanced Quant Finance Course Time Series | Cointegration | Microstructure | Execution | Final System

## Quick Start (must work on a fresh machine)


git clone [Link]
pip install -r [Link]
python [Link]

## Folder Structure
[paste the Day 69 architecture tree here]

Part 2: Are You Ready for a Quant Role? — Honest Self-Assessment


After 10 weeks you have built more than most quant desk candidates who come from a full-time finance
degree. But readiness depends on which type of role you are targeting. Here is an honest assessment by
role type.

ROLE TYPE vs YOUR READINESS AFTER THIS COURSE

JUNIOR ALGO TRADER / QUANT ANALYST (PROP DESK):


Readiness: HIGH (85%)
What you have: backtesting, real costs, walk-forward validation,
statistical significance testing, risk management, live deployment.
What to add: 3 months live paper trading on your deployed system.
Firms: Edelweiss, Kotak, ICICI Securities algo desk.

QUANTITATIVE RESEARCHER (HEDGE FUND):


Readiness: MEDIUM-HIGH (70%)
What you have: factor models, ML alpha, Black-Litterman, GARCH.
What to add: stronger maths (stochastic calculus basics),
Marcos Lopez de Prado "Advances in Financial ML" Chapters 1-8.
Firms: Mirae Asset, DSP, Nippon India quant teams.

DERIVATIVES QUANT / OPTIONS DESK:


Readiness: MEDIUM (65%)
What you have: Black-Scholes, all Greeks, delta hedging,
gamma scalping, VRP, iron condor backtest.
What to add: Sheldon Natenberg "Option Volatility and Pricing".
Study SABR model and vol surface fitting.
Firms: Kotak derivatives desk, ICICI options team.

RISK MANAGEMENT / VaR ANALYST:


Readiness: HIGH (80%)
What you have: 4-method VaR, CVaR, GARCH, factor attribution,
stress testing (5 scenarios), SEBI compliance checklist.
What to add: FRM exam Part 1.
Firms: Bank risk departments, fund compliance teams.

PURE QUANT RESEARCHER (JANE STREET / CITADEL LEVEL):


Readiness: FOUNDATION (40%)
What you have: strong foundation and working systems.
What to add: MSc/PhD in maths, stats, or physics.

Quant Pro | Advanced Quant Finance Course | Week 10 — Elite Layer Page 35
QUANT PRO WEEK 10 | Days 71-78 | ELITE LAYER

Advanced Quant Finance Course Time Series | Cointegration | Microstructure | Execution | Final System

OR 2-3 years of proven alpha on WorldQuant BRAIN.


These roles require graduate-level mathematics and years of track record.

Part 3: Maximum Output from This Course — 20 Tips and Tricks


TIPS 1-5: LEARNING STRATEGY

Tip 1: Read the notes once, then BUILD everything from scratch.
Reading without building = 10% retention. Building = 80% retention.
If you cannot rebuild Day 33 (bootstrap Sharpe CI) from memory,
you have not learned it — you have only read it.

Tip 2: Use one real stock throughout. TCS is mentioned everywhere.


Do not switch between stocks. Deep familiarity with one stock's
behaviour teaches more than shallow familiarity with twenty.

Tip 3: Every time a model gives surprising output, investigate it.


"My Sharpe came out negative" is not a failure — it is a lesson.
Dig into why. Was the period a bear market? Was the cost too high?
Surprises are where the deepest learning happens.

Tip 4: Every week, teach the material to someone.


Explain the p-value concept (Day 33) to a friend. Explain GARCH
(Day 35) to your parents. If you cannot explain it simply, you
have not fully understood it. The Feynman technique works.

Tip 5: Re-read your own code one week after writing it.
If you cannot understand it without the notes, it needs better
variable names and comments. Code you cannot read is code you
cannot maintain or extend.

TIPS 6-10: BACKTESTING AND VALIDATION

Tip 6: ALWAYS report out-of-sample results.


In-sample results are interesting. OOS results are evidence.
If someone asks about your strategy's performance, default to
OOS numbers. Report IS separately and label it clearly.

Tip 7: Minimum 30 trades before trusting any metric.


Win rate from 8 trades is statistically noise.
Sharpe from 12 trades has enormous confidence intervals.
If your strategy trades rarely, either run it over more data
or accept that the sample is too small to be conclusive.

Tip 8: Add realistic costs before any performance claim.


Gross backtest return is a starting point, not a result.
The result is net-of-costs OOS return. STT alone eliminates
many strategies that look attractive before costs.

Tip 9: Plot the equity curve before any other metric.


Numbers can mislead. Sharpe 1.2 sounds good.

Quant Pro | Advanced Quant Finance Course | Week 10 — Elite Layer Page 36
QUANT PRO WEEK 10 | Days 71-78 | ELITE LAYER

Advanced Quant Finance Course Time Series | Cointegration | Microstructure | Execution | Final System

But if the equity curve is flat for 2 years then spikes once,
the strategy is not tradeable — the Sharpe is from one event.
The equity curve shape tells the truth that numbers hide.

Tip 10: Run your strategy on the most recent 12 months.


Markets change. A strategy that worked 2019-2022 may be
dead by 2024. Always test the most recent period separately.
If OOS performance is significantly worse than the historical
average, the strategy may be degrading — investigate before live.

TIPS 11-15: CODING AND PRODUCTION

Tip 11: Use [Link]() every time you filter.


df2 = df[df["SYMBOL"]=="TCS"] — this creates a VIEW, not a copy.
Any modification to df2 may modify df unexpectedly (SettingWithCopyWarning).
Always: df2 = df[df["SYMBOL"]=="TCS"].copy()

Tip 12: Sort by date before every calculation.


pct_change(), rolling(), shift() all assume correct time order.
A DataFrame loaded from CSV is not guaranteed to be sorted.
Always: df = df.sort_values("DATE1").reset_index(drop=True)

Tip 13: shift(1) is not optional — it is a discipline.


Every feature used to predict tomorrow must use .shift(1).
Missing one shift creates data leakage that inflates ML metrics.
Build a checklist: before adding any feature, ask "does this
use tomorrow's data?" If yes, shift(1).

Tip 14: Log everything with timestamps.


When your production system fails at 4 AM, the log is all you have.
Use [Link](handlers=[FileHandler(...)]) from Day 65.
Log: every download success/failure, every signal, every alert sent,
every error with full traceback.

Tip 15: Write unit tests before you refactor.


The test is proof that the original code worked.
After refactoring, the test confirms the new code works too.
Without tests, refactoring is guessing.

TIPS 16-20: CAREER AND COMMUNITY

Tip 16: Post one LinkedIn update per week for 3 months.
Show a chart. Explain one concept. Ask one question.
Consistency matters far more than perfection.
Recruiters searching #quantfinance see consistent builders
as far more credible than silent profiles with impressive CVs.

Tip 17: Submit to WorldQuant BRAIN immediately.


[Link] — free, global, no interview required.
Submit your Week 6 ML features as an "alpha expression".
A portfolio Sharpe above 0.6 on their platform gets you noticed.

Quant Pro | Advanced Quant Finance Course | Week 10 — Elite Layer Page 37
QUANT PRO WEEK 10 | Days 71-78 | ELITE LAYER

Advanced Quant Finance Course Time Series | Cointegration | Microstructure | Execution | Final System

WorldQuant hires directly from BRAIN performers.

Tip 18: Numerai tournament for ongoing ML calibration.


[Link] — submit predictions weekly, earn crypto.
It keeps your ML skills sharp and gives you a public track record.
Your Numerai performance is a quantitative measure of your ML edge.

Tip 19: Read one SSRN paper per week.


[Link] — thousands of free quant finance papers.
Start: Fama-French (1993), Jegadeesh-Titman (1993 momentum),
Black-Scholes (1973), Lopez de Prado (2018 backtest overfitting).
One paper per week = 50 papers per year = genuinely informed.

Tip 20: Build in public, fail in public, learn in public.


Post about the strategy that did not work. Post about the bug
that took you 3 hours to find. Post about the SQL query
that finally worked. The community learns from failure stories
more than success stories. And you build a genuine reputation.

Part 4: Essential Resources — The Complete Reading and Tool List


Resource Type Why It Matters Where to Get

Advances in Financial Book The bible on correct ML Amazon / O'Reilly


ML — Lopez de Prado for finance. Chapters
1-8 are essential.

Option Volatility & Book The options traders' Amazon


Pricing — Natenberg bible. Covers Greeks,
vol, strategies deeply.

Quantitative Trading — Book Practical backtesting, Amazon


Chan Sharpe reality, mean
reversion. Very
readable.

[Link] Papers Free academic research. [Link] (free)


Fama-French, momentum,
VRP all started here.

WorldQuant BRAIN Platform Submit alphas, earn [Link]


recognition, get hired.
Free to join.

Numerai Tournament Platform Weekly ML prediction [Link]


tournament. Crypto
rewards. Public track
record.

QuantConnect Platform Cloud backtesting + [Link]


paper trading. LEAN
engine, professional
grade.

Quant Pro | Advanced Quant Finance Course | Week 10 — Elite Layer Page 38
QUANT PRO WEEK 10 | Days 71-78 | ELITE LAYER

Advanced Quant Finance Course Time Series | Cointegration | Microstructure | Execution | Final System

NSEPython library Python lib Live NSE option chains, pip install nsepython
Bhavcopy, FII data
directly in Python.

arch library (GARCH) Python lib The standard Python pip install arch
GARCH/EGARCH
implementation. Used in
production.

statsmodels Python lib ADF test, ARIMA, OLS pip install statsmodels
regression,
cointegration.
Essential quant
toolkit.

r/algotrading Community 50k+ practitioners. [Link]/r/algotradin


Strategy ideas, library g
discussions, job posts.

QuantLib Library Industry-standard [Link]


C++/Python library for
derivatives pricing at
scale.

Week 10 and Full Course Completion Checklist


• I can run an ADF test, read ACF/PACF plots, and fit ARIMA — and I know when NOT to use ARIMA
(raw stock returns).
• I have implemented the Kalman Filter for dynamic hedge ratios and understand why it beats static OLS.
• I can explain risk parity's advantage over Markowitz and implement it using [Link].
• I understand adverse selection, can compute the Amihud illiquidity ratio, and know the 1% daily volume
rule.
• I can build a VWAP execution schedule that accounts for NSE's U-shaped intraday volume profile.
• I have refactored at least one strategy module to use type hints, docstrings, and passes pytest tests.
• My complete [Link] system runs end-to-end: download, signal, risk, size, store to SQL, alert, log.
• My GitHub README shows OOS performance, architecture diagram, and working quick-start
instructions.
• I have written 20 SQL queries including window functions (AVG OVER, LAG OVER) and CTEs.
• I have submitted to WorldQuant BRAIN or Numerai with my ML signal from Week 6.
• I have a 90-day career plan with specific firms, dates, and weekly actions written down.

# GOLDEN RULE
You started Day 1 not knowing what a DataFrame was. You finish Day 78 with a live trading system on AWS,
a professional GitHub portfolio, 10 validated quant models, a SQL database, a Kalman Filter pairs strategy,
VWAP execution, interview readiness, and a career plan. That is a transformation, not just a course
completion.

Quant Pro | Advanced Quant Finance Course | Week 10 — Elite Layer Page 39
QUANT PRO WEEK 10 | Days 71-78 | ELITE LAYER

Advanced Quant Finance Course Time Series | Cointegration | Microstructure | Execution | Final System

Y
pro
ser
Python · Pandas · GARCH · ML · Options · Risk Parity · Kalman Filter · SQL · VWAP · AWS Cloud ·
Production System G

Quant Pro | Advanced Quant Finance Course | Week 10 — Elite Layer Page 40
QUANT PRO WEEK 10 | Days 71-78 | ELITE LAYER

Advanced Quant Finance Course Time Series | Cointegration | Microstructure | Execution | Final System

WEEK 10 — MASTER CHEATSHEET


Time Series — statsmodels
Function What It Does Key Interpretation

adfuller(series) ADF stationarity test p < 0.05 = stationary. Always


test before regression.

acf(series, nlags=25) Autocorrelation function Bars beyond 1.96/sqrt(n) =


significant autocorrelation

pacf(series, nlags=25) Partial autocorrelation PACF cut-off at p -> AR(p). ACF


cut-off at q -> MA(q)

ARIMA(series, Fit ARIMA model d=0 for returns (already


order=(p,d,q)).fit() stationary)

coint(series1, series2) Engle-Granger cointegration p < 0.05 = cointegrated pair.


Test before pairs trading.

half_life = -ln(2)/lambda Mean reversion speed 5-30 days = tradeable. >60 days
= too slow.

Portfolio Optimisation — [Link]


Method Key Formula When to Use

Markowitz Max Sharpe max (w@mu - rf) / sqrt(w@cov@w) Research only. Unstable for live
trading.

Risk Parity min sum((w_i * MRC_i - Production. No expected returns


target)^2) needed.

Black-Litterman Blend Pi (equilibrium) with When you have ML views to


views Q express as portfolio tilts

Resampled Frontier Bootstrap 1000 paths, average When Markowitz concentration is


weights unacceptable

Equal Weight w_i = 1/n for all i Strongest naive benchmark. Often
beats optimised.

SQL Quick Reference


SQL Construct Purpose Pandas Equivalent

SELECT ... FROM ... WHERE Filter and project df[condition][columns]

GROUP BY ... ORDER BY Aggregate and sort [Link](...).agg(...).sort_va


lues(...)

AVG(col) OVER (PARTITION BY sym 20-day rolling mean [Link]("sym")["col"].rolling


ORDER BY date ROWS 19 PRECEDING) (20).mean()

Quant Pro | Advanced Quant Finance Course | Week 10 — Elite Layer Page 41
QUANT PRO WEEK 10 | Days 71-78 | ELITE LAYER

Advanced Quant Finance Course Time Series | Cointegration | Microstructure | Execution | Final System

LAG(col) OVER (PARTITION BY sym Previous row in group [Link]("sym")["col"].shift(1


ORDER BY date) )

WITH cte AS (SELECT ...) Common Table Expression — build Assign result to variable, reuse
and reuse later

pd.read_sql(query, engine) Load SQL result into DataFrame The production bridge: SQL
stores, Pandas analyses

Execution and Microstructure


Concept Formula or Rule Practical Note

Bid-ask spread Ask price - Bid price Always buy at ask, sell at bid —
never midprice

Adverse selection Largest spread component (~40%) Wider spreads in illiquid stocks
= more informed flow

Amihud illiquidity |Return| / Volume_Rs_Cr Higher = avoid for large orders.


Use to rank stocks.

TWAP Total shares / N time slots Simple, predictable, ignores


volume patterns

VWAP Vol_profile_pct x Total shares Better than TWAP. Matches


natural market volume.

Implementation Shortfall (Exec_price - Decision_price) x The complete true cost from


Qty decision to fill

1% daily volume rule Never trade >1% of avg daily Beyond this threshold, you start
volume moving the market

Complete Course Summary — All 10 Weeks


Week Theme Key Outputs Critical Skills

1-2 Python + Market Data Bhavcopy EDA, OHLC Pandas, NumPy,


charts, returns, vol, Matplotlib, data
RSI cleaning

3 Strategy + Backtesting SMA crossover, PnL, Backtest loop, metrics,


Sharpe, drawdown, bot risk management

4 10 Quant Models BS, MC, Portfolio Opt, Full quant model


ML, Pairs, VaR toolkit built in Python

5 Production Foundation GARCH, live data, real Statistical validation,


costs, walk-forward regime detection

6 ML Done Properly SHAP, TimeSeriesSplit, Feature engineering,


sentiment, regime ML CV, interpretability

7 Options Mastery Delta hedging, gamma Greeks surfaces, VRP,


scalp, iron condor F&O; data intelligence

Quant Pro | Advanced Quant Finance Course | Week 10 — Elite Layer Page 42
QUANT PRO WEEK 10 | Days 71-78 | ELITE LAYER

Advanced Quant Finance Course Time Series | Cointegration | Microstructure | Execution | Final System

8 Portfolio & Risk Pro Kelly, Fama-French, Factor attribution,


stress tests, SQL, SEBI professional risk
report

9 Infrastructure + Career Cloud deploy, interview AWS EC2, event-driven


prep, tearsheet, system BT, 90-day plan

10 Elite Layer + Kalman, risk parity, Time series,


Completion VWAP, SQL mastery, microstructure, full
final system

Quant Pro | Advanced Quant Finance Course | Week 10 — Elite Layer Page 43

You might also like