A technical exploration project documenting my journey of adapting quantitative finance models to e-commerce pricing scenarios.
This is a technical exploration project documenting my thought process of adapting the Market Maker Model from financial quantitative trading to e-commerce dynamic pricing scenarios.
Core Question: E-commerce pricing is essentially a real-time risk pricing problem — finding the optimal balance between transaction probability, profit margin, and return risk. This is strikingly similar to the market maker problem in financial markets.
Traditional e-commerce pricing is static: Cost + Desired Margin = Price
But in reality:
- Higher price → Higher return rate (higher customer expectations)
- Higher inventory → Need to lower prices to clear stock
- More intense competition → Profit margins get squeezed
This is essentially a risk pricing problem.
Financial markets have developed mature risk pricing frameworks over decades:
| Financial Concept | E-commerce Mapping |
|---|---|
| Bid-Ask Spread | Price adjustment range |
| Inventory Risk | Inventory overstock risk |
| Adverse Selection | High return rate customer selection |
| Greeks (Delta/Gamma) | Price sensitivity risk |
New SKUs have no historical data, so traditional ML models don't work. However:
- Different SKUs share common patterns
- We can use meta-learning to learn "how to learn"
- Only 5-10 orders needed for effective pricing
┌─────────────────────────────────────────────────────────────┐
│ Pricing Engine Architecture │
├─────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ Input Layer │────→│ Model Layer │────→│ Output Layer│ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
│ │ │ │ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ SKU Features│ │ Market Maker│ │ Optimal │ │
│ │ Market State│ │ Meta-Learn │ │ Price │ │
│ │ Inventory │ │ Greeks Risk │ │ Confidence │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘
Core Idea: Price is not just cost-plus, but the result of expected profit maximization.
# Pseudocode: Core optimization equation
def expected_profit(price, cost, return_rate, demand):
"""
E[Π] = (P - C) · (1 - R(P)) · Q(P) - C_ret · R(P) · Q(P) - H(q)
Where:
- P: Selling price
- C: Cost
- R(P): Return rate (function of price)
- Q(P): Demand (function of price)
- C_ret: Return cost
- H(q): Inventory holding cost
"""
revenue = (price - cost) * (1 - return_rate(price)) * demand(price)
return_cost = return_cost * return_rate(price) * demand(price)
inventory_cost = inventory_holding_cost(inventory_level)
return revenue - return_cost - inventory_cost
# Optimal price (analytical solution)
def optimal_price(cost, return_rate, elasticity):
"""
P* = (|ε| / (|ε| - 1)) · (C + (R · C_ret) / (1 - R))
This is the risk-adjusted optimal price:
- First term is the markup coefficient (Lerner index variant)
- Second term is the risk-adjusted effective cost
"""
markup = abs(elasticity) / (abs(elasticity) - 1)
risk_adjusted_cost = cost + (return_rate * return_cost) / (1 - return_rate)
return markup * risk_adjusted_costKey Insights:
- Return rate R is an endogenous function of price P (higher price → higher return rate)
- Optimal price automatically includes risk premium
- Price elasticity ε determines pricing power
Problem: Return rate depends not only on price but also on multiple factors.
# Pseudocode: Multi-factor return rate model
def return_rate(price, user_segment, season, competition):
"""
R(P, u, t, C) = R_base(P) × θ(u) × φ(t) × ψ(C)
Where:
- R_base(P): Base return rate (Logistic function)
- θ(u): User type multiplier (high vs low return risk users)
- φ(t): Time dynamic factor (seasonality, promotion periods)
- ψ(C): Competition environment factor (competitor price pressure)
"""
base_rate = logistic(price, R_min=0.05, R_max=0.5, k=0.01)
user_multiplier = get_user_risk_multiplier(user_segment)
seasonal_factor = get_seasonal_factor(season)
competition_factor = get_competition_pressure(competition)
return base_rate * user_multiplier * seasonal_factor * competition_factorKey Insights:
- User segmentation can significantly reduce return rate prediction error
- Seasonal factors are crucial during Double 11, Black Friday, etc.
- Competition environment affects customer expectations, thus return rates
Problem: New SKUs have no historical data, how to price?
# Pseudocode: MAML meta-learning
class MAML_Pricing:
"""
Model-Agnostic Meta-Learning for Cold Start
Core Idea:
1. Pre-train meta-model on large amounts of historical SKU data
2. When facing new SKU, only k samples needed for fast adaptation
3. Combine with expert policy as fallback
Result: Cold start period from 50-100 orders → 5-10 orders
"""
def meta_train(self, historical_sku_tasks):
"""
Meta-training: Train on multiple SKU tasks
for task in historical_sku_tasks:
# Clone meta-model
task_model = clone(self.meta_model)
# Inner loop: Adapt on support set
for step in range(inner_steps):
loss = compute_loss(task_model, task.support_set)
task_model = sgd_update(task_model, loss, inner_lr)
# Outer loop: Compute meta loss on query set
meta_loss += compute_loss(task_model, task.query_set)
# Update meta-model
meta_optimizer.step(meta_loss)
"""
pass
def adapt(self, new_sku_features, k_observations):
"""
Fast adaptation to new SKU
Only k observations needed (k=5-10)
"""
# Meta-model generates initial policy
initial_policy = self.meta_model.generate_policy(new_sku_features)
# Online adaptation
adapted_policy = fast_adapt(initial_policy, k_observations)
# Compute confidence
confidence = evaluate_confidence(adapted_policy, k_observations)
return adapted_policy, confidence
def get_price(self, state, confidence):
"""
Hybrid strategy: Meta-learning + Expert fallback
"""
ml_price = self.meta_model.predict(state)
expert_price = self.expert_policy.predict(state)
# Weight by confidence
if confidence < threshold:
# Low confidence, rely more on expert policy
return blend(ml_price, expert_price, weight=confidence)
else:
return ml_priceKey Insights:
- Meta-learning learns "how to learn", not specific policies
- Different SKUs share transferable patterns
- Expert policy fallback ensures stability
Problem: How to measure the risk of pricing decisions?
# Pseudocode: Greeks risk metrics using auto-differentiation
def calculate_greeks(profit_function, price, params):
"""
Use JAX auto-differentiation for precise derivative calculation
Greeks are risk metrics from options pricing:
- Delta: First-order sensitivity of profit to price
- Gamma: Second-order sensitivity of profit to price (convexity)
- Vega: Sensitivity of profit to volatility
- Rho: Sensitivity of profit to inventory
"""
# JAX auto-differentiation (precise, no truncation error)
delta = jax.grad(profit_function)(price, params)
gamma = jax.hessian(profit_function)(price, params)
# Cross Greeks
cross_gamma = jax.hessian(profit_with_volatility)(price, volatility)
return {
'Delta': delta, # Price sensitivity
'Gamma': gamma, # Convexity risk
'Vanna': cross_gamma # Price-volatility joint risk
}
# Risk circuit breaker mechanism
def risk_circuit_breaker(greeks, thresholds):
"""
When risk metrics exceed thresholds, trigger circuit breaker
"""
if abs(greeks['Delta']) > thresholds['Delta']:
return "TRIGGERED", "Price sensitivity exceeds safe range"
if greeks['Gamma'] < thresholds['Gamma']:
return "TRIGGERED", "Convexity risk too high"
return "NORMAL", "Risk metrics normal"Key Insights:
- Auto-differentiation provides precise derivatives, no truncation error
- Greeks can provide early risk warnings
- Circuit breaker mechanism prevents catastrophic pricing
Problem: How to balance accuracy and latency?
# Pseudocode: Tiered pricing engine
class TieredPricingEngine:
"""
Three-tier architecture balancing latency and accuracy
Tier 1: Hot data (<10ms, 80% requests) - L1 Cache
Tier 2: Warm data (<50ms, 15% requests) - Redis + Light model
Tier 3: Cold data (<200ms, 5% requests) - Full DRL model
Weighted average: P99 < 25ms
"""
def get_price(self, sku_id, context):
# Determine SKU heat
if is_hot_sku(sku_id):
# Tier 1: Local cache
price = l1_cache.get(sku_id)
if price:
return price, tier=1, latency=<10ms
if is_warm_sku(sku_id):
# Tier 2: Redis + ONNX light model
features = redis.get_features(sku_id)
price = onnx_model.predict(features)
l1_cache.put(sku_id, price)
return price, tier=2, latency=<50ms
# Tier 3: Full DRL model
features = get_full_features(sku_id, context)
price = ray_serve_drl_model.predict(features)
redis.put(sku_id, price)
l1_cache.put(sku_id, price)
return price, tier=3, latency=<200msKey Insights:
- 80% of requests take the fastest path (cache)
- LRU cache achieves O(1) read/write
- Fallback strategy ensures availability
A: Traditional methods assume demand is exogenous, but in reality:
- Price affects demand (endogeneity problem)
- Return rate is a function of price
- Inventory level affects pricing strategy
Market maker models naturally handle this endogeneity problem.
A: Main challenges:
- Meta-model training requires large amounts of SKU data (>10,000 SKUs recommended)
- New categories may be out of distribution (OOD detection needed)
- Online adaptation requires real-time feedback (latency issues)
Solution: Hybrid strategy + Expert fallback
A: Yes, but need adaptation:
- Delta → Price sensitivity (pricing decisions)
- Gamma → Convexity risk (price adjustment magnitude)
- Vega → Return rate volatility (quality risk)
Key is threshold calibration and real-time monitoring.
- Avellaneda & Stoikov (2008) - High-frequency trading in a limit order book
- Finn et al. (2017) - Model-Agnostic Meta-Learning for Fast Adaptation
- Black & Scholes (1973) - The pricing of options and corporate liabilities
- Background: Quantitative Finance + Machine Learning + E-commerce Systems
- Interest: Applying financial theory to real business problems
- Contact: siyaohe0618@gmail.com
MIT License - Welcome to discuss and exchange ideas!
Disclaimer: This project is for technical exploration. Code is pseudocode implementation for demonstrating architectural design and technical thinking.