跳轉到

擴充 FinLab 開發指南

本文說明如何貢獻程式碼、設定開發環境、遵循程式碼風格,以及如何擴充 FinLab 的功能。

開發環境設定

1. Fork 與 Clone 專案

# Fork finlab-python/finlab 到你的 GitHub 帳號

# Clone 你的 fork
git clone https://github.com/YOUR_USERNAME/finlab.git
cd finlab

# 新增 upstream remote
git remote add upstream https://github.com/finlab-python/finlab.git

2. 安裝開發依賴

# 使用 uv 管理依賴
pip install uv

# 安裝所有開發依賴
uv sync --all-groups

# 或使用 pip
pip install -e ".[dev,docs,test]"

3. 執行測試

# 執行所有測試
uv run pytest

# 執行特定測試
uv run pytest tests/backtest_test.py

# 執行測試並產生覆蓋率報告
uv run pytest --cov=finlab --cov-report=html

程式碼風格指南

Python 風格

遵循 PEP 8Google Python Style Guide

# 好的範例
def calculate_moving_average(prices, window=20):
    """計算移動平均

    Args:
        prices (pd.Series): 價格序列
        window (int): 視窗大小,預設 20

    Returns:
        pd.Series: 移動平均序列
    """
    return prices.rolling(window).mean()

# 不好的範例
def calc_ma(p, w=20):  # 命名不清楚
    return p.rolling(w).mean()  # 缺少文檔

Docstring 格式

使用 Google 風格:

def sim(position, resample='M', **kwargs):
    """執行回測

    Args:
        position (pd.DataFrame): 持倉訊號
        resample (str): 重採樣頻率
        **kwargs: 其他參數

    Returns:
        Report: 回測報告物件

    Raises:
        ValueError: 當 position 格式不正確時

    Examples:
        ```python
        position = close > close.average(20)
        report = sim(position, resample='M')
        ```
    """
    pass

擴充功能範例

1. 新增自訂技術指標

finlab/dataframe.py 新增方法:

class FinlabDataFrame(pd.DataFrame):
    # ... 現有程式碼

    def custom_indicator(self, param1, param2=10):
        """自訂技術指標

        Args:
            param1 (float): 參數 1
            param2 (int): 參數 2,預設 10

        Returns:
            FinlabDataFrame: 計算結果
        """
        result = self.rolling(param2).apply(
            lambda x: your_calculation(x, param1)
        )
        return FinlabDataFrame(result)

2. 新增自訂分析模組

繼承 Analysis 類別:

# finlab/analysis/custom_analysis.py
from finlab.analysis import Analysis

class CustomAnalysis(Analysis):

    def calculate_trade_info(self, report):
        """計算額外交易資訊"""
        custom_data = ...  # 你的邏輯
        return [['custom_field', custom_data, 'entry_sig_date']]

    def analyze(self, report):
        """執行分析"""
        trades = report.get_trades()
        result = ...  # 你的分析邏輯
        return result

    def display(self):
        """顯示結果"""
        return self.result

3. 新增自訂市場

繼承 Market 類別:

# finlab/markets/custom.py
from finlab.market import Market
import pandas as pd

class CustomMarket(Market):

    @staticmethod
    def get_name():
        return 'custom_market'

    def get_price(self, trade_at_price='close', adj=True):
        # 你的資料載入邏輯
        df = pd.read_csv('path/to/data.csv')
        return df

測試撰寫指南

測試結構

# tests/test_custom_feature.py
import unittest
from finlab import data
from finlab.dataframe import FinlabDataFrame

class TestCustomFeature(unittest.TestCase):

    def setUp(self):
        """測試前準備"""
        self.close = data.get('price:收盤價')

    def test_custom_indicator(self):
        """測試自訂指標"""
        result = self.close.custom_indicator(param1=0.5, param2=10)

        # 檢查結果型別
        self.assertIsInstance(result, FinlabDataFrame)

        # 檢查結果形狀
        self.assertEqual(result.shape, self.close.shape)

        # 檢查結果值
        self.assertFalse(result.isna().all().all())

    def tearDown(self):
        """測試後清理"""
        pass

貢獻流程

1. 建立分支

# 更新 main 分支
git checkout main
git pull upstream main

# 建立新分支
git checkout -b feature/your-feature-name

2. 開發與測試

# 撰寫程式碼
# ...

# 執行測試
uv run pytest

# 執行 linter
uv run ruff check .
uv run ruff format .

3. 提交程式碼

# 提交變更
git add .
git commit -m "feat: add custom indicator"

# 推送至你的 fork
git push origin feature/your-feature-name

4. 建立 Pull Request

  1. 前往 GitHub 上你的 fork
  2. 點擊 "New Pull Request"
  3. 填寫 PR 描述(說明變更內容與目的)
  4. 等待程式碼審查

參考資源