Docs
Open Studio

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

Strategy Layer

Backtest Layer

Analysis Layer

Trading Layer

finlab.portfolio
Portfolio Management

finlab.online
Live Trading

finlab.analysis
Strategy Analysis

finlab.optimize
Parameter Optimization

finlab.plot
Data Visualization

finlab.backtest
Backtest Engine

finlab.report
Report Generation

finlab.market
Market Objects

finlab.ml.feature
Feature Engineering

finlab.ml.label
Label Generation

finlab.ml.qlib
Model Training

finlab.data
Data Access

finlab.dataframe
FinlabDataFrame

  • Data Layer: finlab.data loads datasets and hands them to FinlabDataFrame for 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.backtest simulates 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.plot draws charts.
  • Trading Layer: finlab.portfolio manages multi-strategy portfolios, and finlab.online sends the orders to your broker.
The full data flow: from data sources to live positions

Technical indicators

Machine learning

Parameter optimization

In-depth analysis

Visualization

Live trading

Data sources
GCS/BigQuery

finlab.data.get

DataFrame

Purpose?

FinlabDataFrame
Compute methods

ml.feature
Feature engineering

Generate signals
bool DataFrame

ml.label
Label generation

ml.qlib
Model training

Predict weights
float DataFrame

finlab.backtest.sim

Report object

Analysis type?

optimize.sim_conditions

analysis module

plot module

online.OrderExecutor

Analysis report

Interactive chart

Broker API

Live positions

What each module does

Click a module name for its API reference.

ModuleMain classes/functionsPurposeDepends on
finlab.dataget()Fetch financial data from the database(none)
finlab.dataframeFinlabDataFrameEnhanced DataFrame with financial computation supportpandas
finlab.backtestsim()Backtest engine for simulating tradesdata, dataframe, market
finlab.reportReportBacktest report and performance analysisbacktest
finlab.optimizesim_conditions(), ReportCollectionTest multiple condition combinationsbacktest
finlab.analysisLiquidityAnalysis, MaeMfeAnalysis, etc.In-depth strategy analysisreport
finlab.marketMarket, USMarket, USFundMarket, TWMarketMarket data and characteristicsdata
finlab.ml.featureta(), combine()ML feature engineeringdata
finlab.ml.labelreturn_percentage(), excess_over_mean(), etc.ML label generationdata
finlab.ml.qlibLGBModel(), XGBModel(), etc.Model trainingml.feature, ml.label
finlab.portfolioPortfolio, PortfolioSyncManagerMulti-strategy portfolio managementreport
finlab.onlineOrderExecutor, SchwabAccount and Taiwan broker accountsLive trading executionreport, portfolio
finlab.plotplot_candles(), StrategyReturnStatsData visualizationdataframe

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:

Report objectfinlab.backtestFinlabDataFramefinlab.dataUserReport objectfinlab.backtestFinlabDataFramefinlab.dataUserdata.get('price:adj_close')DataFrameCompute indicator .average(20)FinlabDataFrameGenerate signal close > ma20bool DataFramesim(position, resample='M')Build Report objectBacktest resultsreport.display()Show performance charts

What the modules pass to each other

Data typeFormatDescriptionExample
Price datapd.DataFrameindex: dates, columns: stock symbolsdata.get('price:adj_close')
Selection signalpd.DataFrame(bool)True = buy, False = not holdingclose > ma20
Position weightpd.DataFrame(float)Values between 0 and 1, the position ratioML model predictions
Trade recordspd.DataFrameDetailed per-trade informationreport.get_trades()
Performance metricsdictThe strategy's statistical indicatorsreport.get_stats()
Benchmark indexpd.SeriesTime series of price dataUSMarket.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:

Yes

No

Condition check
close > ma20

bool DataFrame
True/False

Need exit logic?

hold_until
Add exit condition

Use directly as position

finlab.backtest.sim
Run backtest

Report object
Contains performance and trades

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:

Heatmap

Bar chart

Line chart

Define candidate conditions

Combine into dict

Use sim_conditions

Generate all combinations
2^n - 1 total

Backtest each combination

Collect all Reports

Build ReportCollection

Visualization choice

plot_stats heatmap

plot_stats bar

plot_creturns

Identify best combination

Rerun backtest with 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:

No

Yes

No

Yes

Load raw data
finlab.data

Feature engineering
finlab.ml.feature

Label generation
finlab.ml.label

Model training
finlab.ml.qlib

Predict position weights

Backtest
finlab.backtest.sim

Performance acceptable?

Adjust features or model

Run in-depth analysis

Out-of-sample testing

Validation passed?

Deploy to live trading

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:

Broker APIOrderExecutorAccount objectReport objectUserBroker APIOrderExecutorAccount objectReport objectUserreport.upload(name)Upload succeededreport.position_info()Holdings listConfigure broker accountConnectedOrderExecutor(report, account)Compute buy/sell listexecutor.execute()Submit buy ordersBuy order acksSubmit sell ordersSell order acksExecution completeQuery positionsFetch position infoPosition dataShow live holdings

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 →

See Multi-strategy portfolio.

Extend FinLab: which class to start from

Once you are comfortable with basic backtesting, pick a starting point for what you want to add:

Multi-strategy portfolio

Custom market

Custom analysis

Machine learning

Comfortable with basic backtesting

Development need?

Learn finlab.portfolio
Portfolio management

Subclass Market
Build a custom market

Subclass Analysis
Build analysis modules

Learn finlab.ml
Features, labels, models

Multi-strategy live trading

Backtest overseas markets / crypto

Customized analysis reports

ML-driven strategies

Advanced applications

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.

«abstract»

Market

+get_name() : str

+get_freq() : str

+get_price() : DataFrame

+get_benchmark() : Series

+get_asset_id_to_name() : dict

USMarket

+get_name() : "us_stock"

+get_benchmark() : S&P 500

+get_industry() : dict

+market_close_at_timestamp()

TWMarket

+get_name() : "tw_stock"

+get_benchmark() : TAIEX

+get_industry() : dict

+market_close_at_timestamp()

ROTCMarket

+get_name() : "rotc_stock"

CustomMarket

+custom_data_source

+get_name() : "custom"

Custom analysis: subclass Analysis

Every analysis implements calculate_trade_info(), analyze(), display() and is_market_supported(). For the full method, see Analysis modules.

«abstract»

Analysis

+calculate_trade_info() : list

+analyze() : dict

+display() : Figure

+is_market_supported() : bool

LiquidityAnalysis

+Liquidity risk detection

+Limit-up/down and volume

MaeMfeAnalysis

+Volatility analysis

+12 MAE/MFE subplots

PeriodStatsAnalysis

+Period stability

+Annual and monthly performance

InequalityAnalysis

+Inequality factors

+Gini coefficient

AlphaBetaAnalysis

+Alpha/Beta analysis

DrawdownAnalysis

+Drawdown analysis

CustomAnalysis

+Custom analysis logic

What FinlabDataFrame adds to pandas

FinlabDataFrame subclasses the pandas DataFrame and adds methods for stock selection:

«pandas»

DataFrame

+Basic DataFrame functionality

FinlabDataFrame

+average() : moving average

+is_largest() : ranking

+is_smallest() : ranking

+quantile() : quantiles

+hold_until() : entry/exit sugar

+and_then() : combine logic

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.

Small
Single stock

Medium
Dozens of indicators

Large
Many backtests

Need data

Data size?

Use data.get directly

Load once
Avoid repeated calls

Consider
local caching

Run strategy logic

When the backtest itself is slow:

BottleneckOptimization method
Too many condition combinationsPre-filter with individual conditions, remove poor ones
Data range too largeShorten the backtest period or increase the resample frequency
High computational complexityUse vectorized operations, avoid loops
Insufficient memoryProcess in batches or use longer resample periods

Next steps

New to FinLab? Learn the modules in this order:

Yes

No

Yes

No

Start

Learn finlab.data
Data access

Learn FinlabDataFrame
Indicator calculation

Learn finlab.backtest
Basic backtesting

Learn Report object
Performance analysis

Want to go deeper?

Learn finlab.analysis
In-depth analysis

Start live trading
finlab.online

Learn finlab.optimize
Parameter optimization

Learn the full workflow

Use machine learning?

Learn finlab.ml
ML modules

Mastery!

For more examples, see US market examples and FinLab on GitHub.

↑↓ Move Enter Open Esc Close