QuantCoderFS – Development Update: April 24, 2025
An all-in-one visual overview of QuantCoderFS as of April 2025
Introduction
This platform is designed as a sandbox for rapidly prototyping focused AI workflows in quantitative trading. It currently supports four core use cases:
Insight Extraction: Automatically summarize market trends, research reports, and financial news to surface actionable intelligence.
Academic Literature Research: Retrieve and distill key findings from scholarly papers, helping you stay abreast of cutting-edge quantitative finance methods.
Assisted Algorithm Development: Generate and refine trading strategies in QuantConnect’s Python environment, streamlining backtesting and deployment.
Fundamental Analysis Dashboard: Visualize company fundamentals through an interactive chart interface powered by the EODHD API.
All interactions with language models are logged for two reasons:
Reproducibility: Every AI-driven step can be audited and reconstructed to ensure transparency and compliance.
Continuous Learning: The logs produce valuable data for future model fine-tuning and reinforcement learning, improving performance over time.
Planned extensions include:
Portfolio Management Module: Leverage Monte Carlo simulations and Value-at-Risk (VaR) analytics to optimize asset allocations.
QuantConnect LEAN Integration: Automate backtest optimization and live strategy deployment within the LEAN engine.
Intraday Time‑Series Forecasting: Implement high-frequency data processing to power real-time predictive models.
Live Market Scanner: Continuously scan markets for trading signals and risk alerts.
The goal is to deliver an end-to-end AI lab—flexible, transparent, and extensible—for the next generation of quantitative traders.
AI flows as serializable units
The application is fully modular by design. Each AI flow acts as a self-contained, serializable unit that delegates its execution to an associated agent store. This architecture allows any flow to be easily cloned and adapted to new processes by analogy—just copy the unit and customize its logic.
The current versioned flows include:
Analyse – v1.1 (Modified: 24 April 2025)
Chat with Fundamentals powered by EODHD APIs.Extract – v1.0 (Dated: 15 April 2025)
PDF summarization integrated with Notion for streamlined research workflows.Code – v0.4 (Dated: 15 April 2025)
Code generation for QuantConnect. Performance is currently limited; several enhancements are planned, notably integration with the CrewAI GitHubSearchTool.Research – v1.0 (Dated: 15 April 2025)
Discovery and retrieval of academic articles via ArXiv and CrossRef APIs.
Deterministic Processes
In addition to AI-driven flows, the platform includes deterministic processes—components that perform well-defined, reproducible computations without LLM involvement.
Realtimer
Visualizes intraday OHLCV data. This module will evolve to support real-time market monitoring and alerting.Foliomanager
Calculates portfolio risk and simulates equity performance using Monte Carlo methods. It supports VaR computation and return forecasting.
The article will now present these six core functions—four AI flows and two deterministic processes—in sequence.
Step 1: Search for Relevant Articles on "Momentum Strategies"
We begin by querying academic databases using the keyword "momentum strategies" to identify high-quality, relevant literature.
Search Output:
Step 2: Extract Key Insights from the Selected Article
After downloading one of the identified articles, we proceed to extract its core insights—summarizing the methodology, findings, and implications in a concise, actionable format.
The extracted text can be reviewed, copied, saved, and pushed directly to a dedicated Notion workspace for seamless documentation and further analysis.
Step 3: Can AI Generate a Meaningful Boilerplate Algorithm from These Insights?
Leveraging the extracted insights, we now task the AI with generating a starter algorithm tailored to the strategy.
Below is the interactive dialog with the pair-coding assistant:
The assistant-generated code is reproduced below. It required approximately 10 minutes of debugging with ChatGPT-4o-mini to resolve syntax issues.
However, the algorithm is not placing any trades, indicating a deeper issue with the strategy logic. A thorough review of both the code structure and the original research article is likely needed. The script spans 240 lines, reflecting the underlying complexity of the strategy.
from AlgorithmImports import *
import numpy as np
import pandas as pd
from collections import defaultdict, deque
from sklearn.linear_model import LogisticRegression
from datetime import timedelta
# ----------------------------------
# Custom Models
# ----------------------------------
class CustomFuturesFeeModel(FeeModel):
def __init__(self, commission_per_contract):
self.commission = commission_per_contract
def GetOrderFee(self, parameters: OrderFeeParameters) -> OrderFee:
order = parameters.Order
fee = abs(order.Quantity) * self.commission
return OrderFee(CashAmount(fee, "USD"))
class MySlippageModel(SlippageModel):
"""A simple log-scaled slippage: price * 0.0001 * log10(2 * contracts)"""
def GetSlippageApproximation(self, asset: Security, order: Order) -> float:
qty = float(order.AbsoluteQuantity)
return asset.Price * 0.0001 * np.log10(2 * qty)
# ----------------------------------
# Main Algorithm
# ----------------------------------
class DynamicMomentumTrendFollowing(QCAlgorithm):
def Initialize(self):
# 1. Basic setup
self.SetStartDate(2020, 1, 1)
self.SetCash(1e6)
self.UniverseSettings.Resolution = Resolution.Daily
# 2. Futures universe (expand to your full list of 56 tickers)
self.future_symbols = [
Futures.Indices.SP500EMini, Futures.Indices.NASDAQ100EMini,
Futures.Indices.Dow30EMini, Futures.Indices.Russell2000EMini,
Futures.Financials.Y30TreasuryBond, Futures.Financials.Y10TreasuryNote,
Futures.Metals.Gold, Futures.Energies.CrudeOilWTI,
# …and so on up to 56 instruments
]
for fut in self.future_symbols:
self.AddFuture(fut, Resolution.Daily, dataNormalizationMode=DataNormalizationMode.BackwardsRatio)
# 3. Rolling windows & lookbacks
self.lookbacks = [21, 63, 126, 189, 252]
self.rolling_window_years = 3
self.rolling_days = 252 * self.rolling_window_years
# 4. Risk & sizing params
self.rebalance_interval = 21
self.target_volatility = 0.10
self.max_gross_leverage = 2.0
self.max_instrument_leverage = 1.0
self.drawdown_threshold = 0.20
self.drawdown_reduction = 0.5
# 5. Cost models
self.commission_per_contract = 1.5
self.slippage_per_contract = 2.0 # unused now, since we use MySlippageModel
# 6. Data structures
self.price_history = defaultdict(lambda: deque(maxlen=self.rolling_days + max(self.lookbacks) + 2))
self.returns_history = defaultdict(lambda: deque(maxlen=self.rolling_days + max(self.lookbacks)))
self.models = {} # symbol → {lookback: model}
self.model_scores = {} # symbol → {lookback: deque}
self.model_weights = {} # symbol → {lookback: weight}
self.active_contracts = {} # canonical → Symbol
self.portfolio_equity = []
self.max_portfolio_value = 0
self.drawdown_active = False
# 7. Warm-up & scheduling
self.SetWarmUp(self.rolling_days + max(self.lookbacks) + 2)
self.EnableAutomaticIndicatorWarmUp = True
self.Schedule.On(self.DateRules.MonthStart(), self.TimeRules.AfterMarketOpen("SPY", 30), self.Rebalance)
# 8. Apply custom fee & slippage
self.SetSecurityInitializer(self.CustomSecurityInitializer)
def CustomSecurityInitializer(self, security: Security):
security.SetFeeModel(CustomFuturesFeeModel(self.commission_per_contract))
security.SetSlippageModel(MySlippageModel())
def OnData(self, data: Slice):
# 1. Update histories for the front-month of each future
for chain in data.FuturesChains.Values:
canonical = chain.Symbol.ID.Symbol
# pick the nearest contract >10 days to expiry
contracts = [c for c in chain if c.Expiry > self.Time + timedelta(days=10)]
if not contracts: continue
front = sorted(contracts, key=lambda x: x.Expiry)[0]
sym = front.Symbol
self.active_contracts[canonical] = sym
if not data.Bars.ContainsKey(sym): continue
price = data.Bars[sym].Close
hist = self.price_history[sym]
if len(hist):
ret = price/hist[-1] - 1
self.returns_history[sym].append(ret)
hist.append(price)
# 2. Track drawdown
cur_val = self.Portfolio.TotalPortfolioValue
self.max_portfolio_value = max(self.max_portfolio_value, cur_val)
dd = 1 - cur_val/self.max_portfolio_value
if dd > self.drawdown_threshold and not self.drawdown_active:
self.drawdown_active = True
self.Debug(f"Drawdown > {self.drawdown_threshold*100:.0f}% — cutting risk.")
elif dd <= self.drawdown_threshold and self.drawdown_active:
self.drawdown_active = False
def Rebalance(self):
if self.IsWarmingUp: return
signals = {}
vols = {}
probs = {}
# 3. Fit/update models and generate signals
for canonical, sym in self.active_contracts.items():
rets = list(self.returns_history[sym])
if len(rets) < self.rolling_days + max(self.lookbacks):
continue
# build X, y in one loop
X, y = [], []
for i in range(max(self.lookbacks), len(rets)-1):
feats = [
np.prod([1 + rets[i - lb + 1 + j] for j in range(lb)]) - 1
for lb in self.lookbacks
]
X.append(feats)
y.append(int(rets[i+1] > 0))
X, y = np.array(X), np.array(y)
# init containers
self.models.setdefault(sym, {})
self.model_scores.setdefault(sym, {})
self.model_weights.setdefault(sym, {})
# train models
for lb in self.lookbacks:
if lb not in self.models[sym]:
self.models[sym][lb] = LogisticRegression(solver="lbfgs", max_iter=200, warm_start=True)
try:
self.models[sym][lb].fit(X, y)
except Exception as e:
self.Debug(f"Fit failed {sym} lb={lb}: {e}")
# score on last observation
pred = self.models[sym][lb].predict(X[-1].reshape(1, -1))[0]
actual = y[-1]
dq = self.model_scores[sym].setdefault(lb, deque(maxlen=60))
dq.append(int(pred == actual))
# compute DMA weights
acc = np.array([np.mean(self.model_scores[sym][lb]) for lb in self.lookbacks])
if acc.sum() == 0:
w = np.ones_like(acc) / len(acc)
else:
es = np.exp(acc - np.max(acc))
w = es / es.sum()
for i, lb in enumerate(self.lookbacks):
self.model_weights[sym][lb] = w[i]
# predict next-day probability
latest_feats = [
np.prod([1 + rets[-lb + j] for j in range(lb)]) - 1
for lb in self.lookbacks
]
ps = []
for lb in self.lookbacks:
try:
p = self.models[sym][lb].predict_proba(np.array(latest_feats).reshape(1, -1))[0,1]
except:
p = 0.5
ps.append(p)
combined = np.dot(w, ps)
probs[sym] = combined
signals[sym] = 1 if combined > 0.5 else -1 if combined < 0.5 else 0
# 21-day vol estimate
vols[sym] = np.std(rets[-21:]) * np.sqrt(252)
if not signals:
self.Debug("No signals this month.")
return
# 4. Risk-parity weight calc
inv_vol = np.array([1/vols[s] if vols[s]>0 else 0 for s in signals])
raw_w = inv_vol / inv_vol.sum()
if self.drawdown_active:
raw_w *= self.drawdown_reduction
# scale to target vol
port_vol = np.sqrt((raw_w**2 * np.array([vols[s]**2 for s in signals])).sum())
scale = self.target_volatility / port_vol if port_vol>0 else 1
final_w = raw_w * scale
# cap gross leverage
gross = abs(final_w).sum()
if gross > self.max_gross_leverage:
final_w *= self.max_gross_leverage/gross
# 5. Set targets in one go
targets = []
pv = self.Portfolio.TotalPortfolioValue
for i, sym in enumerate(signals):
dir_ = signals[sym]
w = np.clip(final_w[i] * dir_, -self.max_instrument_leverage, self.max_instrument_leverage)
targets.append(PortfolioTarget(sym, w))
self.SetHoldings(targets)
# 6. Plotting
self.Plot("Portfolio", "GrossLeverage", gross)
self.Plot("Portfolio", "Scale", scale)
for sym, p in probs.items():
self.Plot("Signal", str(sym), p)
Step 4: I've Heard About NUTX's Strong Performance—Should I Jump In?
Let’s use the platform to investigate NUTX, a stock that’s reportedly delivered exceptional returns over the past year.
(Note: This analysis is for demonstration purposes only and does not constitute financial advice.)
Step 5: How Long Did It Take to Generate This Executive Summary?
As a benchmark example, the generation of this executive summary took 34 seconds, according to the system logs.
Step 6: How Does NUTX Perform Intraday?
To assess NUTX’s behavior on shorter timeframes, we visualize its intraday OHLCV data and look for notable patterns in price action, volume, and volatility.
Step 7: What Is the Impact on a Portfolio?
To evaluate NUTX’s potential role in a broader investment strategy, we run a portfolio simulation. The results are shown below:
Conclusion
This platform addresses a broad range of needs for quantitative traders and investors—ranging from research and summarization to strategy prototyping, market monitoring, and portfolio analysis.
While the coding workflow remains a bottleneck due to performance limitations, active development is underway to enhance its reliability and capabilities.
Your feedback is highly appreciated—feel free to share your thoughts or suggestions on how this tool could better serve your workflow.
Thank you for your time and interest.
Best regards,
S.M.L