Architecture
Module architecture
On this page8
This page uses diagrams to show how FinLab's modules divide the work and how data moves between them. Start here to understand how FinLab is built, or before you extend it.
The big picture: from the data layer up to trading
FinLab is built in layers, with the Data Layer at the bottom and the Trading Layer at the top. Data flows upward:
- Data Layer:
finlab.dataloads datasets and hands them toFinlabDataFramefor computation. - Strategy Layer: when a machine learning model picks the positions, data goes through feature engineering (
finlab.ml.feature), label generation (finlab.ml.label) and model training (finlab.ml.qlib). Ordinary stock-selection rules skip this layer and go straight to the backtest. - Backtest Layer:
finlab.backtestsimulates trades with a market object (finlab.market) and produces a backtest report (finlab.report). - Analysis Layer: use the report for in-depth analysis (
finlab.analysis) or parameter optimization (finlab.optimize, which runs backtests again);finlab.plotdraws charts. - Trading Layer:
finlab.portfoliomanages multi-strategy portfolios, andfinlab.onlinesends the orders to your broker.
The full data flow: from data sources to live positions
What each module does
Click a module name for its API reference.
| Module | Main classes/functions | Purpose | Depends on |
|---|---|---|---|
| finlab.data | get() | Fetch financial data from the database | (none) |
| finlab.dataframe | FinlabDataFrame | Enhanced DataFrame with financial computation support | pandas |
| finlab.backtest | sim() | Backtest engine for simulating trades | data, dataframe, market |
| finlab.report | Report | Backtest report and performance analysis | backtest |
| finlab.optimize | sim_conditions(), ReportCollection | Test multiple condition combinations | backtest |
| finlab.analysis | LiquidityAnalysis, MaeMfeAnalysis, etc. | In-depth strategy analysis | report |
| finlab.market | Market, USMarket, USFundMarket, TWMarket | Market data and characteristics | data |
| finlab.ml.feature | ta(), combine() | ML feature engineering | data |
| finlab.ml.label | return_percentage(), excess_over_mean(), etc. | ML label generation | data |
| finlab.ml.qlib | LGBModel(), XGBModel(), etc. | Model training | ml.feature, ml.label |
| finlab.portfolio | Portfolio, PortfolioSyncManager | Multi-strategy portfolio management | report |
| finlab.online | OrderExecutor, SchwabAccount and Taiwan broker accounts | Live trading execution | report, portfolio |
| finlab.plot | plot_candles(), StrategyReturnStats | Data visualization | dataframe |
From data to a backtest report: the basic flow
A strategy takes as few as four steps: load data, compute an indicator, write the holding rule and hand it to sim().
from finlab import data
from finlab.backtest import sim
data.set_market('us')
close = data.get('price:adj_close')
position = close > close.average(20)
report = sim(position, resample='M')
report.display()How that code moves between the modules:
What the modules pass to each other
| Data type | Format | Description | Example |
|---|---|---|---|
| Price data | pd.DataFrame | index: dates, columns: stock symbols | data.get('price:adj_close') |
| Selection signal | pd.DataFrame(bool) | True = buy, False = not holding | close > ma20 |
| Position weight | pd.DataFrame(float) | Values between 0 and 1, the position ratio | ML model predictions |
| Trade records | pd.DataFrame | Detailed per-trade information | report.get_trades() |
| Performance metrics | dict | The strategy's statistical indicators | report.get_stats() |
| Benchmark index | pd.Series | Time series of price data | USMarket.get_benchmark() (S&P 500) |
A rule produces a table of True/False. If you need exit logic, add it with hold_until first; otherwise use the table as the position for sim() directly:
Common workflows
A complete strategy goes roughly through: data → indicator calc → signal generation → parameter optimization → in-depth analysis → out-of-sample test → live trading. Here is how the main stages work.
Test many condition combinations at once
Combine your candidate conditions into a dict and pass it to sim_conditions(). It generates every combination (2^n - 1 for n conditions), backtests each one and collects the results in a ReportCollection. Compare them with a heatmap, bar chart or line chart, then rerun the backtest with the best combination:
For details, see Strategy optimization.
Let machine learning set the position weights
Engineer features, generate labels and train a model, then backtest the weights it predicts. If performance falls short, adjust the features or the model; once it is acceptable, run in-depth analysis and out-of-sample tests, and deploy to live trading only after validation passes:
For the full steps, see the ML strategy workflow.
Take a backtest to live trading
Upload the strategy with report.upload(name), get the holdings list with report.position_info(), configure your broker account and hand both to OrderExecutor, which computes the buy/sell list and submits the orders:
For setup, see Orders: one strategy.
Combine several strategies into one portfolio
Pass the reports of several strategies to Portfolio, then let PortfolioSyncManager sync them to live trading:
Strategy A report →
Strategy B report → Portfolio → PortfolioSyncManager → multi-strategy live trading
Strategy C report →Extend FinLab: which class to start from
Once you are comfortable with basic backtesting, pick a starting point for what you want to add:
Custom markets: subclass Market
Market defines what every market must provide: its name, frequency, prices, benchmark and the ID-to-name map. The US and Taiwan markets are its subclasses. For the full method, see Custom markets.
Custom analysis: subclass Analysis
Every analysis implements calculate_trade_info(), analyze(), display() and is_market_supported(). For the full method, see Analysis modules.
What FinlabDataFrame adds to pandas
FinlabDataFrame subclasses the pandas DataFrame and adds methods for stock selection:
To contribute your changes back to FinLab, see Extending FinLab.
Make backtests faster
Load each dataset once and reuse it, instead of calling data.get() again for every backtest; for many backtests, consider local caching. For how the cache works, see Data flow.
When the backtest itself is slow:
| Bottleneck | Optimization method |
|---|---|
| Too many condition combinations | Pre-filter with individual conditions, remove poor ones |
| Data range too large | Shorten the backtest period or increase the resample frequency |
| High computational complexity | Use vectorized operations, avoid loops |
| Insufficient memory | Process in batches or use longer resample periods |
Next steps
New to FinLab? Learn the modules in this order:
- Strategy optimization Compare many condition combinations at once with
sim_conditions(). - Analysis modules Liquidity, MAE/MFE, period stability and other in-depth analysis.
- Custom markets Subclass
Marketto backtest your own data. - Research to production Every step from research and validation to live trading.
For more examples, see US market examples and FinLab on GitHub.
Was this page helpful?