Skip to content

Commit a9876e8

Browse files
committed
Add UDP Receiver, Black-Litterman, and SDE Solver
1 parent f392b95 commit a9876e8

File tree

4 files changed

+270
-6
lines changed

4 files changed

+270
-6
lines changed
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
{
2+
"cells": [
3+
{
4+
"cell_type": "markdown",
5+
"metadata": {},
6+
"source": [
7+
"# Advanced Asset Allocation: Black-Litterman Model\n",
8+
"\n",
9+
"The Black-Litterman model overcomes the \"estimation error\" problem in Mean-Variance Optimization (Markowitz) by starting with a neutral equilibrium and overlaying subjective investor views.\n",
10+
"\n",
11+
"**The Formula:**\n",
12+
"$$E[R] = [(\tau \Sigma)^{-1} + P^T \Omega^{-1} P]^{-1} [(\tau \Sigma)^{-1} \Pi + P^T \Omega^{-1} Q]$$",
13+
"\n",
14+
"**Components:**\n",
15+
"1. **Prior ($\Pi$):** Implied equilibrium returns (from Market Cap).\n",
16+
"2. **Views ($Q$):** Investor's subjective views on asset returns.\n",
17+
"3. **Pick Matrix ($P$):** Maps views to specific assets.\n",
18+
"4. **Uncertainty ($\Omega$):** Confidence in the views."
19+
]
20+
},
21+
{
22+
"cell_type": "code",
23+
"execution_count": null,
24+
"metadata": {},
25+
"outputs": [],
26+
"source": [
27+
"import numpy as np\n",
28+
"import pandas as pd\n",
29+
"import matplotlib.pyplot as plt\n",
30+
"\n",
31+
"def black_litterman(W_mkt, Sigma, Q, P, tau=0.05, delta=2.5):\n",
32+
" \"\"\"\n",
33+
" Black-Litterman Implementation.\n",
34+
" :param W_mkt: Market weights (nx1)\n",
35+
" :param Sigma: Covariance matrix (nxn)\n",
36+
" :param Q: View returns (kx1)\n",
37+
" :param P: Pick matrix (kxn)\n",
38+
" :param tau: Scalar for uncertainty\n",
39+
" :param delta: Risk aversion coefficient\n",
40+
" \"\"\"\n",
41+
" # 1. Calculate Implied Equilibrium Returns (Pi)\n",
42+
" # Pi = delta * Sigma * W_mkt\n",
43+
" Pi = delta * np.dot(Sigma, W_mkt)\n",
44+
" \n",
45+
" # 2. Uncertainty of Views (Omega)\n",
46+
" # Common heuristic: Omega = diag(P * (tau * Sigma) * P^T)\n",
47+
" Omega = np.diag(np.diag(np.dot(np.dot(P, tau * Sigma), P.T)))\n",
48+
" \n",
49+
" # 3. New Combined Return Vector\n",
50+
" term1 = np.linalg.inv(np.linalg.inv(tau * Sigma) + np.dot(np.dot(P.T, np.linalg.inv(Omega)), P))\n",
51+
" term2 = np.dot(np.linalg.inv(tau * Sigma), Pi) + np.dot(np.dot(P.T, np.linalg.inv(Omega)), Q)\n",
52+
" \n",
53+
" E_R = np.dot(term1, term2)\n",
54+
" return E_R\n",
55+
"\n",
56+
"# Mock Data (3 Assets: Tech, Energy, Finance)\n",
57+
"W_mkt = np.array([0.5, 0.3, 0.2])\n",
58+
"Sigma = np.array([\n",
59+
" [0.04, 0.01, 0.02],\n",
60+
" [0.01, 0.09, 0.01],\n",
61+
" [0.02, 0.01, 0.05]\n",
62+
"])\n",
63+
"\n",
64+
"# Views: \n",
65+
"# 1. Tech will outperform Energy by 5% (Relative)\n",
66+
"# 2. Finance will have absolute return of 10% (Absolute)\n",
67+
"Q = np.array([0.05, 0.10])\n",
68+
"P = np.array([\n",
69+
" [1, -1, 0], # Tech - Energy\n",
70+
" [0, 0, 1] # Finance\n",
71+
"])\n",
72+
"\n",
73+
"res = black_litterman(W_mkt, Sigma, Q, P)\n",
74+
"\n",
75+
"print(\"Equilibrium Returns (Prior):\", (2.5 * np.dot(Sigma, W_mkt)))\n",
76+
"print(\"Black-Litterman Returns:\", res)\n",
77+
"\n",
78+
"# Plotting\n",
79+
"assets = ['Tech', 'Energy', 'Finance']\n",
80+
"plt.bar(assets, res, alpha=0.7, label='B-L Returns')\n",
81+
"plt.bar(assets, 2.5 * np.dot(Sigma, W_mkt), alpha=0.5, label='Prior')\n",
82+
"plt.legend()\n",
83+
"plt.title('Black-Litterman Posterior vs Prior Returns')\n",
84+
"plt.show()"
85+
]
86+
}
87+
],
88+
"metadata": {
89+
"kernelspec": {
90+
"display_name": "Python 3",
91+
"language": "python",
92+
"name": "python3"
93+
},
94+
"language_info": {
95+
"codemirror_mode": {
96+
"name": "ipython",
97+
"version": 3
98+
},
99+
"file_extension": ".py",
100+
"mimetype": "text/x-python",
101+
"name": "python",
102+
"nbconvert_exporter": "python",
103+
"pygments_lexer": "ipython3",
104+
"version": "3.8.5"
105+
}
106+
},
107+
"nbformat": 4,
108+
"nbformat_minor": 4
109+
}
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import numpy as np
2+
import matplotlib.pyplot as plt
3+
4+
def euler_maruyama(drift_func, diffusion_func, x0, T, dt):
5+
"""
6+
Euler-Maruyama Numerical Solver for SDE: dX = a(X,t)dt + b(X,t)dW
7+
"""
8+
N = int(T / dt)
9+
t = np.linspace(0, T, N+1)
10+
X = np.zeros(N+1)
11+
X[0] = x0
12+
13+
for i in range(N):
14+
dW = np.random.normal(0, np.sqrt(dt))
15+
X[i+1] = X[i] + drift_func(X[i], t[i]) * dt + diffusion_func(X[i], t[i]) * dW
16+
17+
return t, X
18+
19+
# Example 1: Geometric Brownian Motion (GBM)
20+
# dS = mu*S*dt + sigma*S*dW
21+
mu = 0.1
22+
sigma = 0.2
23+
24+
gbm_drift = lambda S, t: mu * S
25+
gbm_diffusion = lambda S, t: sigma * S
26+
27+
t_gbm, S_gbm = euler_maruyama(gbm_drift, gbm_diffusion, x0=100, T=1, dt=0.001)
28+
29+
# Example 2: Vasicek Model (Mean Reverting)
30+
# dr = kappa*(theta - r)*dt + sigma*dW
31+
kappa = 3.0
32+
theta = 0.05
33+
sig_vas = 0.03
34+
35+
vas_drift = lambda r, t: kappa * (theta - r)
36+
vas_diffusion = lambda r, t: sig_vas
37+
38+
t_vas, r_vas = euler_maruyama(vas_drift, vas_diffusion, x0=0.02, T=1, dt=0.001)
39+
40+
# Plotting
41+
fig, ax = plt.subplots(2, 1, figsize=(10, 8))
42+
43+
ax[0].plot(t_gbm, S_gbm)
44+
ax[0].set_title('GBM Simulation (Euler-Maruyama)')
45+
ax[0].grid(True)
46+
47+
ax[1].plot(t_vas, r_vas, color='orange')
48+
ax[1].set_title('Vasicek Model Simulation (Mean Reversion)')
49+
ax[1].grid(True)
50+
51+
plt.tight_layout()
52+
plt.show()
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
#include <iostream>
2+
#include <sys/socket.h>
3+
#include <netinet/in.h>
4+
#include <arpa/inet.h>
5+
#include <unistd.h>
6+
#include <cstring>
7+
#include <vector>
8+
9+
/**
10+
* Mock UDP Multicast Receiver for Market Data.
11+
*
12+
* In HFT, Market Data (e.g., NASDAQ TotalView-ITCH) is typically
13+
* delivered via UDP Multicast.
14+
*
15+
* Key Concepts:
16+
* 1. Non-blocking sockets (using fcntl).
17+
* 2. UDP Multicast Group joining.
18+
* 3. Raw byte parsing into structs.
19+
*/
20+
21+
#pragma pack(push, 1)
22+
struct MarketUpdate {
23+
char msg_type; // 'A' for Add, 'E' for Execute
24+
uint32_t symbol_id;
25+
uint32_t price;
26+
uint32_t quantity;
27+
};
28+
#pragma pack(pop)
29+
30+
class MarketDataReceiver {
31+
private:
32+
int sockfd;
33+
struct sockaddr_in addr;
34+
35+
public:
36+
MarketDataReceiver(const char* ip, int port) {
37+
// 1. Create UDP Socket
38+
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
39+
if (sockfd < 0) {
40+
perror("socket");
41+
exit(1);
42+
}
43+
44+
// 2. Allow multiple sockets to use the same PORT
45+
int reuse = 1;
46+
setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (char *)&reuse, sizeof(reuse));
47+
48+
// 3. Setup Address
49+
memset(&addr, 0, sizeof(addr));
50+
addr.sin_family = AF_INET;
51+
addr.sin_addr.s_addr = htonl(INADDR_ANY);
52+
addr.sin_port = htons(port);
53+
54+
// 4. Bind
55+
if (bind(sockfd, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
56+
perror("bind");
57+
exit(1);
58+
}
59+
60+
// 5. Join Multicast Group (Simplified Mock)
61+
struct ip_mreq mreq;
62+
mreq.imr_multiaddr.s_addr = inet_addr(ip);
63+
mreq.imr_interface.s_addr = htonl(INADDR_ANY);
64+
// setsockopt(sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *)&mreq, sizeof(mreq));
65+
66+
std::cout << "Listening for Market Data on " << ip << ":" << port << "..." << std::endl;
67+
}
68+
69+
void receive_loop() {
70+
char buffer[1024];
71+
struct sockaddr_in from;
72+
socklen_t fromlen = sizeof(from);
73+
74+
while (true) {
75+
ssize_t n = recvfrom(sockfd, buffer, sizeof(buffer), 0, (struct sockaddr*)&from, &fromlen);
76+
if (n < 0) break;
77+
78+
if (n >= sizeof(MarketUpdate)) {
79+
MarketUpdate* update = reinterpret_cast<MarketUpdate*>(buffer);
80+
process_update(*update);
81+
}
82+
}
83+
}
84+
85+
void process_update(const MarketUpdate& update) {
86+
std::cout << "Msg: " << update.msg_type
87+
<< " | SymID: " << update.symbol_id
88+
<< " | Price: " << update.price / 10000.0
89+
<< " | Qty: " << update.quantity << std::endl;
90+
}
91+
92+
~MarketDataReceiver() {
93+
close(sockfd);
94+
}
95+
};
96+
97+
int main() {
98+
// Note: This won't run without a live UDP stream,
99+
// but demonstrates the boilerplate required in HFT interviews.
100+
std::cout << "--- UDP Market Data Feed Handler Mock ---" << std::endl;
101+
// MarketDataReceiver receiver("233.0.0.1", 12345);
102+
// receiver.receive_loop();
103+
return 0;
104+
}

README.md

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -33,17 +33,16 @@ We have curated specialized resources that target the specific requirements of H
3333

3434
### ⚡ Low Latency & Systems
3535
* **C++ Mastery:** [Order Matching Engine](./06_quantitative_development/cpp_low_latency/examples/order_matching_engine.cpp), [Lock-Free Queue](./06_quantitative_development/cpp_low_latency/examples/lock_free_spsc_queue.cpp), & [Memory Pool](./06_quantitative_development/cpp_low_latency/examples/memory_pool.cpp).
36-
* **Optimization:** [Microbenchmark Utils](./06_quantitative_development/cpp_low_latency/examples/microbenchmark_utils.hpp) (CPU Cycle Counting).
36+
* **Networking:** [UDP Market Data Receiver](./06_quantitative_development/cpp_low_latency/examples/udp_receiver_mock.cpp) (Multicast & Non-blocking).
37+
* **Optimization:** [Microbenchmark Utils](./06_quantitative_development/cpp_low_latency/examples/microbenchmark_utils.hpp).
3738
* **Concurrency:** [Multithreaded Monte Carlo](./06_quantitative_development/cpp_low_latency/examples/multithreaded_monte_carlo.cpp).
38-
* **Template Metaprogramming:** [Compile-Time Greeks](./06_quantitative_development/cpp_low_latency/examples/compile_time_greeks.cpp).
39-
* **Architecture:** [HFT Infrastructure](./06_quantitative_development/system_design/architecture_notes/hft_architecture.md).
4039

4140
### 🧠 Interview Mastery
4241
* **The Roadmap:** [8-Week Study Plan](./07_interview_preparation/study_roadmap.md).
43-
* **Quant Strategies:** [Avellaneda-Stoikov MM](./05_algorithmic_trading/strategies/market_microstructure/avellaneda_stoikov_mm.py), [Pairs Trading](./05_algorithmic_trading/strategies/systematic_strategies/pairs_trading_stat_arb.ipynb), & [Execution Algos (TWAP/VWAP)](./05_algorithmic_trading/strategies/execution/execution_algos.py).
42+
* **Portfolio Construction:** [Black-Litterman Model](./03_financial_engineering/portfolio_optimization/black_litterman_model.ipynb) (Advanced optimization).
43+
* **Stochastic Calculus:** [SDE Solver (Euler-Maruyama)](./03_financial_engineering/stochastic_calculus/sde_solver_euler_maruyama.py).
44+
* **Quant Strategies:** [Avellaneda-Stoikov MM](./05_algorithmic_trading/strategies/market_microstructure/avellaneda_stoikov_mm.py) & [Pairs Trading](./05_algorithmic_trading/strategies/systematic_strategies/pairs_trading_stat_arb.ipynb).
4445
* **Visual Intuition:** [Options Greeks Dashboard](./03_financial_engineering/derivatives_pricing/greeks_visualization.ipynb).
45-
* **AI/ML:** [LSTM Time Series Forecasting](./04_machine_learning_and_ai/deep_learning/lstm_price_prediction.ipynb).
46-
* **Backtesting:** [Performance Metrics Library](./05_algorithmic_trading/backtesting_frameworks/performance_metrics.py).
4746
* **Jane Street Guide:** [Probability & Betting](./07_interview_preparation/company_insights/jane_street_guide.md).
4847

4948
---

0 commit comments

Comments
 (0)