阅读提示

这篇面向需要在团队中使用 Betalens 的开发者,讲解 YAML 规范、因子模板、版本控制和 CI 钩子。学完之后,你能建立一套适合团队的研究协作规范。

导言

当团队里有多个人同时用 Betalens 研究时,会遇到几个协作问题:

  • 因子脚本格式不统一,每个人有自己的写法。
  • YAML 配置散落在各处,没有统一的版本管理。
  • 回测产物(Excel/HTML/parquet)没有统一的归档规则。
  • 多人修改同一因子时容易产生冲突。

这篇给出 Betalens 框架下的协作约定建议。

YAML 规范:四个最小 block

每个因子 YAML 必须包含以下四个 block:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
meta:
class: xxx # 因子家族目录名(必需)
name: xxx # 因子名(必需,且唯一)
source: 来源 # 可选
formula: 公式 # 可选
logic: 逻辑 # 可选

factor_spec: # 因子计算配置(必需)
inputs: {...}
compute_kwargs: {...}
direction: positive
table_name: daily_market

weight: # 权重生成配置(必需)
mode: classic-long-short
long_groups: null
short_groups: null

run: # 运行配置(必需)
start_date: '2024-01-01'
end_date: '2024-12-31'
rebal_freq: W
n_quantiles: 10
initial_amount: 100000000
output_dir: outputs/runs/manual

不要做多层覆盖。每个因子 YAML 是自包含的完整配置,不存在”继承”机制。

因子家族模板

如果团队要开发某一类因子(如”技术指标”类),可以先创建一个家族模板:

1
2
3
4
betalens-factor/
tech_indicators/ # 新建家族
class_tech_indicators.yaml # 家族元数据
factor_template_tech_indicators.py # 通用模板

家族模板可以包含:

  • 通用的 compute 框架
  • 统一的日志记录
  • 共享的常量定义

新增因子时:

1
2
3
4
betalens-factor/tech_indicators/
RSI/
factor_RSI.py # 继承或引用模板
factor_RSI.yaml

版本控制:git 约定

推荐的 .gitignore

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# Betalens 本体
betalens-factor/*/outputs/
betalens-factor/*/*/outputs/
logs/
*.log

# 数据库配置(包含密码)
**/config.local.json
**/config.json

# Python
__pycache__/
*.pyc
.venv/
.eggs/
*.egg-info/

# Node(Dashboard 前端)
dashboard/node_modules/
dashboard/dist/

# 回测产物
*.xlsx
*.html
*.parquet

# Jupyter
.ipynb_checkpoints/

推荐提交的目录

1
2
3
4
5
6
7
8
9
# 提交这些
betalens-factor/*/
betalens-factor/*/*/factor_*.py
betalens-factor/*/*/factor_*.yaml
docs/
tests/
dashboard/main.py
dashboard/routers/
dashboard/services/

CI 钩子

可以用 GitHub Actions 做自动化检查:

1. YAML 格式校验

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# .github/workflows/validate-yaml.yml
name: Validate Factor YAMLs

on: [push, pull_request]

jobs:
validate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.11'
- name: Validate YAML structure
run: |
python -c "
import yaml, glob
for path in glob.glob('betalens-factor/**/*.yaml', recursive=True):
with open(path) as f:
cfg = yaml.safe_load(f)
required = ['meta', 'factor_spec', 'weight', 'run']
missing = [k for k in required if k not in cfg]
if missing:
print(f'ERROR {path}: missing {missing}')
exit(1)
print('All YAMLs valid')
"

2. 因子脚本 import 测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# .github/workflows/test-factors.yml
name: Test Factor Imports

on: [push, pull_request]

jobs:
import-test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.11'
- name: Install dependencies
run: pip install betalens
- name: Test factor imports
run: |
python -c "
import glob, importlib.util
for path in glob.glob('betalens-factor/**/*.py', recursive=True):
if 'factor_' in path and not path.endswith('__init__.py'):
spec = importlib.util.spec_from_file_location('factor', path)
module = importlib.util.module_from_spec(spec)
try:
spec.loader.exec_module(module)
print(f'OK {path}')
except Exception as e:
print(f'FAIL {path}: {e}')
exit(1)
"

3. 回测快速冒烟测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# .github/workflows/smoke-test.yml
name: Backtest Smoke Test

on:
schedule:
- cron: '0 2 * * *' # 每天凌晨跑一次
workflow_dispatch:

jobs:
smoke:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.11'
- name: Run smoke tests
run: pytest tests/test_smoke.py -v --tb=short

协作流程建议

1
2
3
4
5
1. 新建因子分支:git checkout -b factor/ILLIQ_v2
2. 在 betalens-factor/<class>/<NAME>/ 下创建文件
3. push 并开 PR,CI 自动跑 YAML 校验 + import 测试
4. Review 通过后合并到 main
5. Dashboard 刷新因子列表

常见问题

1. YAML 被 git 误标为二进制

1
2
3
# 添加 .gitattributes
*.yaml text
*.py text

2. CI 环境里没有数据库

CI 测试只做 YAML 校验和 import 测试,不需要数据库。真正的回测测试需要单独的集成测试环境(或只在本地跑)。

3. 多人在同一个因子上改代码

使用 Git 的 conflict resolution 功能解决 YAML 冲突。Python 脚本冲突建议线下沟通后由一人主导合并。

延伸阅读