quantcli 0.1.10__tar.gz → 0.1.11__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. {quantcli-0.1.10/quantcli.egg-info → quantcli-0.1.11}/PKG-INFO +1 -1
  2. {quantcli-0.1.10 → quantcli-0.1.11}/pyproject.toml +1 -1
  3. {quantcli-0.1.10 → quantcli-0.1.11}/quantcli/cli.py +43 -73
  4. {quantcli-0.1.10 → quantcli-0.1.11/quantcli.egg-info}/PKG-INFO +1 -1
  5. {quantcli-0.1.10 → quantcli-0.1.11}/tests/test_builtin_factors.py +89 -68
  6. {quantcli-0.1.10 → quantcli-0.1.11}/LICENSE +0 -0
  7. {quantcli-0.1.10 → quantcli-0.1.11}/README.md +0 -0
  8. {quantcli-0.1.10 → quantcli-0.1.11}/quantcli/core/__init__.py +0 -0
  9. {quantcli-0.1.10 → quantcli-0.1.11}/quantcli/core/backtest.py +0 -0
  10. {quantcli-0.1.10 → quantcli-0.1.11}/quantcli/core/data.py +0 -0
  11. {quantcli-0.1.10 → quantcli-0.1.11}/quantcli/core/factor.py +0 -0
  12. {quantcli-0.1.10 → quantcli-0.1.11}/quantcli/datasources/__init__.py +0 -0
  13. {quantcli-0.1.10 → quantcli-0.1.11}/quantcli/datasources/akshare.py +0 -0
  14. {quantcli-0.1.10 → quantcli-0.1.11}/quantcli/datasources/baostock.py +0 -0
  15. {quantcli-0.1.10 → quantcli-0.1.11}/quantcli/datasources/base.py +0 -0
  16. {quantcli-0.1.10 → quantcli-0.1.11}/quantcli/datasources/cache.py +0 -0
  17. {quantcli-0.1.10 → quantcli-0.1.11}/quantcli/datasources/fundamentals/__init__.py +0 -0
  18. {quantcli-0.1.10 → quantcli-0.1.11}/quantcli/datasources/fundamentals/provider.py +0 -0
  19. {quantcli-0.1.10 → quantcli-0.1.11}/quantcli/datasources/mixed.py +0 -0
  20. {quantcli-0.1.10 → quantcli-0.1.11}/quantcli/datasources/mysql.py +0 -0
  21. {quantcli-0.1.10 → quantcli-0.1.11}/quantcli/datasources/sync/__init__.py +0 -0
  22. {quantcli-0.1.10 → quantcli-0.1.11}/quantcli/datasources/sync/akshare.py +0 -0
  23. {quantcli-0.1.10 → quantcli-0.1.11}/quantcli/datasources/sync/base.py +0 -0
  24. {quantcli-0.1.10 → quantcli-0.1.11}/quantcli/datasources/sync/gm.py +0 -0
  25. {quantcli-0.1.10 → quantcli-0.1.11}/quantcli/datasources/sync/gm_fundamental.py +0 -0
  26. {quantcli-0.1.10 → quantcli-0.1.11}/quantcli/factors/__init__.py +0 -0
  27. {quantcli-0.1.10 → quantcli-0.1.11}/quantcli/factors/base.py +0 -0
  28. {quantcli-0.1.10 → quantcli-0.1.11}/quantcli/factors/compute.py +0 -0
  29. {quantcli-0.1.10 → quantcli-0.1.11}/quantcli/factors/loader.py +0 -0
  30. {quantcli-0.1.10 → quantcli-0.1.11}/quantcli/factors/pipeline.py +0 -0
  31. {quantcli-0.1.10 → quantcli-0.1.11}/quantcli/factors/ranking.py +0 -0
  32. {quantcli-0.1.10 → quantcli-0.1.11}/quantcli/factors/ranking_executor.py +0 -0
  33. {quantcli-0.1.10 → quantcli-0.1.11}/quantcli/factors/screening.py +0 -0
  34. {quantcli-0.1.10 → quantcli-0.1.11}/quantcli/factors/screening_executor.py +0 -0
  35. {quantcli-0.1.10 → quantcli-0.1.11}/quantcli/models/bar.py +0 -0
  36. {quantcli-0.1.10 → quantcli-0.1.11}/quantcli/parser/__init__.py +0 -0
  37. {quantcli-0.1.10 → quantcli-0.1.11}/quantcli/parser/constants.py +0 -0
  38. {quantcli-0.1.10 → quantcli-0.1.11}/quantcli/parser/formula.py +0 -0
  39. {quantcli-0.1.10 → quantcli-0.1.11}/quantcli/utils/__init__.py +0 -0
  40. {quantcli-0.1.10 → quantcli-0.1.11}/quantcli/utils/env.py +0 -0
  41. {quantcli-0.1.10 → quantcli-0.1.11}/quantcli/utils/logger.py +0 -0
  42. {quantcli-0.1.10 → quantcli-0.1.11}/quantcli/utils/path.py +0 -0
  43. {quantcli-0.1.10 → quantcli-0.1.11}/quantcli/utils/symbol_utils.py +0 -0
  44. {quantcli-0.1.10 → quantcli-0.1.11}/quantcli/utils/time.py +0 -0
  45. {quantcli-0.1.10 → quantcli-0.1.11}/quantcli/utils/validate.py +0 -0
  46. {quantcli-0.1.10 → quantcli-0.1.11}/quantcli.egg-info/SOURCES.txt +0 -0
  47. {quantcli-0.1.10 → quantcli-0.1.11}/quantcli.egg-info/dependency_links.txt +0 -0
  48. {quantcli-0.1.10 → quantcli-0.1.11}/quantcli.egg-info/entry_points.txt +0 -0
  49. {quantcli-0.1.10 → quantcli-0.1.11}/quantcli.egg-info/requires.txt +0 -0
  50. {quantcli-0.1.10 → quantcli-0.1.11}/quantcli.egg-info/top_level.txt +0 -0
  51. {quantcli-0.1.10 → quantcli-0.1.11}/setup.cfg +0 -0
  52. {quantcli-0.1.10 → quantcli-0.1.11}/tests/test_akshare_integration.py +0 -0
  53. {quantcli-0.1.10 → quantcli-0.1.11}/tests/test_cli.py +0 -0
  54. {quantcli-0.1.10 → quantcli-0.1.11}/tests/test_datasources.py +0 -0
  55. {quantcli-0.1.10 → quantcli-0.1.11}/tests/test_factors.py +0 -0
  56. {quantcli-0.1.10 → quantcli-0.1.11}/tests/test_gm_executors.py +0 -0
  57. {quantcli-0.1.10 → quantcli-0.1.11}/tests/test_mixed_datasource.py +0 -0
  58. {quantcli-0.1.10 → quantcli-0.1.11}/tests/test_multi_factor.py +0 -0
  59. {quantcli-0.1.10 → quantcli-0.1.11}/tests/test_pipeline_integration.py +0 -0
  60. {quantcli-0.1.10 → quantcli-0.1.11}/tests/test_symbol_utils.py +0 -0
  61. {quantcli-0.1.10 → quantcli-0.1.11}/tests/test_time.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: quantcli
3
- Version: 0.1.10
3
+ Version: 0.1.11
4
4
  Summary: 面向AI的多因子量化选股策略挖掘工具,AI Agent 友好 CLI
5
5
  Author-email: QuantCLI Team <quantcli@example.com>
6
6
  Project-URL: repository, https://github.com/wumu2013/quantcli
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "quantcli"
7
- version = "0.1.10"
7
+ version = "0.1.11"
8
8
  description = "面向AI的多因子量化选股策略挖掘工具,AI Agent 友好 CLI"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.9"
@@ -277,68 +277,6 @@ def data_sync_fundamentals(ctx, years):
277
277
  sys.exit(1)
278
278
 
279
279
 
280
- # =============================================================================
281
- # Factors 命令 - 列出内置因子
282
- # =============================================================================
283
-
284
-
285
- @quantcli.group()
286
- def factors():
287
- """内置因子管理"""
288
- pass
289
-
290
-
291
- @factors.command("list")
292
- @click.option("--json", is_flag=True, help="Output as JSON")
293
- @click.pass_context
294
- def factors_list(ctx, json):
295
- """列出所有内置 Alpha101 因子"""
296
- from .utils import builtin_factors_dir
297
-
298
- builtin_dir = builtin_factors_dir() / "alpha101"
299
-
300
- if not builtin_dir.exists():
301
- click.echo("No built-in factors found")
302
- return
303
-
304
- # 加载所有因子
305
- factors = []
306
- for f in sorted(builtin_dir.glob("alpha_*.yaml")):
307
- import yaml
308
-
309
- with open(f, "r", encoding="utf-8") as fp:
310
- data = yaml.safe_load(fp)
311
- factors.append(
312
- {
313
- "name": data.get("name", f.stem),
314
- "type": data.get("type", "technical"),
315
- "direction": data.get("direction", "neutral"),
316
- "description": data.get("description", ""),
317
- "file": f"alpha101/{f.name}",
318
- }
319
- )
320
-
321
- if json:
322
- import json
323
-
324
- click.echo(
325
- json.dumps(
326
- {"status": "success", "count": len(factors), "factors": factors},
327
- ensure_ascii=False,
328
- indent=2,
329
- )
330
- )
331
- return
332
-
333
- click.echo(f"Built-in Alpha101 Factors ({len(factors)} total):\n")
334
- click.echo(f"{'File':<22} {'Type':<12} {'Direction':<10} Description")
335
- click.echo("-" * 60)
336
- for f in factors:
337
- click.echo(
338
- f"{f['file']:<22} {f['type']:<12} {f['direction']:<10} {f['description']}"
339
- )
340
-
341
-
342
280
  # =============================================================================
343
281
  # Factor 命令
344
282
  # =============================================================================
@@ -469,21 +407,53 @@ def factor_eval(ctx, name, symbol, start, end, method):
469
407
 
470
408
 
471
409
  @factor.command("list")
410
+ @click.option("--json", is_flag=True, help="Output as JSON")
472
411
  @click.pass_context
473
- def factor_list(ctx):
474
- """列出已注册的因子"""
475
- engine = FactorEngine()
476
- factors = engine.registry.list_all()
412
+ def factor_list(ctx, json):
413
+ """列出所有内置 Alpha101 因子"""
414
+ from .utils import builtin_factors_dir
477
415
 
478
- if not factors:
479
- click.echo("No factors registered")
416
+ builtin_dir = builtin_factors_dir() / "alpha101"
417
+
418
+ if not builtin_dir.exists():
419
+ click.echo("No built-in factors found")
480
420
  return
481
421
 
482
- click.echo("Registered factors:")
483
- for name in factors:
484
- factor = engine.registry.get(name)
485
- if factor:
486
- click.echo(f" - {name}: {factor.formula[:50]}...")
422
+ factors = []
423
+ for f in sorted(builtin_dir.glob("alpha_*.yaml")):
424
+ import yaml
425
+
426
+ with open(f, "r", encoding="utf-8") as fp:
427
+ data = yaml.safe_load(fp)
428
+ factors.append(
429
+ {
430
+ "name": data.get("name", f.stem),
431
+ "type": data.get("type", "technical"),
432
+ "direction": data.get("direction", "neutral"),
433
+ "description": data.get("description", ""),
434
+ "file": f"alpha101/{f.name}",
435
+ }
436
+ )
437
+
438
+ if json:
439
+ import json
440
+
441
+ click.echo(
442
+ json.dumps(
443
+ {"status": "success", "count": len(factors), "factors": factors},
444
+ ensure_ascii=False,
445
+ indent=2,
446
+ )
447
+ )
448
+ return
449
+
450
+ click.echo(f"Built-in Alpha101 Factors ({len(factors)} total):\n")
451
+ click.echo(f"{'File':<22} {'Type':<12} {'Direction':<10} Description")
452
+ click.echo("-" * 60)
453
+ for f in factors:
454
+ click.echo(
455
+ f"{f['file']:<22} {f['type']:<12} {f['direction']:<10} {f['description']}"
456
+ )
487
457
 
488
458
 
489
459
  @factor.command("run-file")
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: quantcli
3
- Version: 0.1.10
3
+ Version: 0.1.11
4
4
  Summary: 面向AI的多因子量化选股策略挖掘工具,AI Agent 友好 CLI
5
5
  Author-email: QuantCLI Team <quantcli@example.com>
6
6
  Project-URL: repository, https://github.com/wumu2013/quantcli
@@ -18,7 +18,11 @@ import numpy as np
18
18
  from click.testing import CliRunner
19
19
 
20
20
  from quantcli import cli
21
- from quantcli.factors.loader import load_strategy, load_all_factors, load_factor_from_ref
21
+ from quantcli.factors.loader import (
22
+ load_strategy,
23
+ load_all_factors,
24
+ load_factor_from_ref,
25
+ )
22
26
  from quantcli.factors.pipeline import FactorPipeline
23
27
 
24
28
 
@@ -38,15 +42,17 @@ def sample_price_data():
38
42
  open_ = close * (1 + np.random.randn(100) * 0.01)
39
43
  volume = np.random.randint(1000000, 10000000, 100)
40
44
 
41
- return pd.DataFrame({
42
- "date": dates,
43
- "symbol": ["600519"] * 100,
44
- "open": open_,
45
- "high": close * 1.02,
46
- "low": close * 0.98,
47
- "close": close,
48
- "volume": volume,
49
- })
45
+ return pd.DataFrame(
46
+ {
47
+ "date": dates,
48
+ "symbol": ["600519"] * 100,
49
+ "open": open_,
50
+ "high": close * 1.02,
51
+ "low": close * 0.98,
52
+ "close": close,
53
+ "volume": volume,
54
+ }
55
+ )
50
56
 
51
57
 
52
58
  @pytest.fixture
@@ -60,25 +66,27 @@ def multi_symbol_price_data():
60
66
 
61
67
  for symbol in symbols:
62
68
  close = 100 + np.cumsum(np.random.randn(60) * 0.5)
63
- data[symbol] = pd.DataFrame({
64
- "date": dates,
65
- "symbol": [symbol] * 60,
66
- "open": close * (1 + np.random.randn(60) * 0.01),
67
- "high": close * 1.02,
68
- "low": close * 0.98,
69
- "close": close,
70
- "volume": np.random.randint(1000000, 10000000, 60),
71
- })
69
+ data[symbol] = pd.DataFrame(
70
+ {
71
+ "date": dates,
72
+ "symbol": [symbol] * 60,
73
+ "open": close * (1 + np.random.randn(60) * 0.01),
74
+ "high": close * 1.02,
75
+ "low": close * 0.98,
76
+ "close": close,
77
+ "volume": np.random.randint(1000000, 10000000, 60),
78
+ }
79
+ )
72
80
 
73
81
  return data
74
82
 
75
83
 
76
- class TestFactorsListCommand:
77
- """quantcli factors list 命令测试"""
84
+ class TestFactorBuiltinListCommand:
85
+ """quantcli factor list 命令测试"""
78
86
 
79
- def test_factors_list_basic(self, runner):
80
- """测试 factors list 基本功能"""
81
- result = runner.invoke(cli.factors_list, ["--json"])
87
+ def test_factor_list_builtin_basic(self, runner):
88
+ """测试 factor list 基本功能"""
89
+ result = runner.invoke(cli.factor_list, ["--json"])
82
90
 
83
91
  assert result.exit_code == 0
84
92
  output = json.loads(result.output)
@@ -87,20 +95,19 @@ class TestFactorsListCommand:
87
95
  assert output["count"] == 40
88
96
  assert len(output["factors"]) == 40
89
97
 
90
- def test_factors_list_shows_alpha101(self, runner):
91
- """测试 factors list 显示 Alpha101 因子"""
92
- result = runner.invoke(cli.factors_list, ["--json"])
98
+ def test_factor_list_builtin_shows_alpha101(self, runner):
99
+ """测试 factor list 显示 Alpha101 因子"""
100
+ result = runner.invoke(cli.factor_list, ["--json"])
93
101
 
94
102
  assert result.exit_code == 0
95
103
  output = json.loads(result.output)
96
104
 
97
- # 检查包含 alpha_001
98
105
  factor_files = [f["file"] for f in output["factors"]]
99
106
  assert "alpha101/alpha_001.yaml" in factor_files
100
107
 
101
- def test_factors_list_human_format(self, runner):
102
- """测试 factors list 人类友好格式"""
103
- result = runner.invoke(cli.factors_list, [])
108
+ def test_factor_list_builtin_human_format(self, runner):
109
+ """测试 factor list 人类友好格式"""
110
+ result = runner.invoke(cli.factor_list, [])
104
111
 
105
112
  assert result.exit_code == 0
106
113
  assert "Built-in Alpha101 Factors" in result.output
@@ -113,7 +120,9 @@ class TestBuiltinFactors:
113
120
 
114
121
  def test_load_single_builtin_factor(self):
115
122
  """测试加载单个内置因子"""
116
- factor = load_factor_from_ref("/Users/apple/quantcli/examples/strategies", "alpha101/alpha_001")
123
+ factor = load_factor_from_ref(
124
+ "/Users/apple/quantcli/examples/strategies", "alpha101/alpha_001"
125
+ )
117
126
 
118
127
  assert factor is not None
119
128
  assert "alpha_001" in factor.name.lower() or "反转" in factor.description
@@ -135,7 +144,9 @@ class TestBuiltinFactors:
135
144
 
136
145
  def test_builtin_factor_fields(self):
137
146
  """测试内置因子字段完整"""
138
- factor = load_factor_from_ref("/Users/apple/quantcli/examples/strategies", "alpha101/alpha_008")
147
+ factor = load_factor_from_ref(
148
+ "/Users/apple/quantcli/examples/strategies", "alpha101/alpha_008"
149
+ )
139
150
 
140
151
  assert factor is not None
141
152
  assert factor.name is not None
@@ -156,7 +167,9 @@ class TestBuiltinFactors:
156
167
  # 测试每个因子都能加载
157
168
  for yaml_file in yaml_files:
158
169
  alpha_name = yaml_file.stem # alpha_001
159
- factor = load_factor_from_ref("/Users/apple/quantcli/examples/strategies", f"alpha101/{alpha_name}")
170
+ factor = load_factor_from_ref(
171
+ "/Users/apple/quantcli/examples/strategies", f"alpha101/{alpha_name}"
172
+ )
160
173
  assert factor is not None, f"Failed to load {yaml_file.name}"
161
174
 
162
175
 
@@ -248,8 +261,8 @@ class TestAnalyzeCommands:
248
261
  window = 20
249
262
  ic_rolling = []
250
263
  for i in range(window, len(factor)):
251
- f = factor.iloc[i-window:i]
252
- r = forward_returns.iloc[i-window:i]
264
+ f = factor.iloc[i - window : i]
265
+ r = forward_returns.iloc[i - window : i]
253
266
  valid_mask = ~(f.isna() | r.isna())
254
267
  if valid_mask.sum() > 5:
255
268
  ic, _ = spearmanr(f[valid_mask], r[valid_mask])
@@ -268,7 +281,7 @@ class TestFilterRunCommand:
268
281
 
269
282
  def test_filter_config_loading(self, tmp_path):
270
283
  """测试 filter 配置加载"""
271
- with tempfile.NamedTemporaryFile(mode='w', suffix='.yaml', delete=False) as f:
284
+ with tempfile.NamedTemporaryFile(mode="w", suffix=".yaml", delete=False) as f:
272
285
  f.write("""
273
286
  name: 测试策略
274
287
  version: 1.0.0
@@ -293,6 +306,7 @@ output:
293
306
  assert config.name == "测试策略"
294
307
  finally:
295
308
  import os
309
+
296
310
  os.unlink(config_path)
297
311
 
298
312
  def test_filter_with_weights(self, tmp_path, multi_symbol_price_data):
@@ -300,7 +314,7 @@ output:
300
314
  from quantcli.factors.compute import FactorComputer
301
315
  from quantcli.factors.ranking import ScoringEngine
302
316
 
303
- with tempfile.NamedTemporaryFile(mode='w', suffix='.yaml', delete=False) as f:
317
+ with tempfile.NamedTemporaryFile(mode="w", suffix=".yaml", delete=False) as f:
304
318
  f.write("""
305
319
  name: 测试策略
306
320
  version: 1.0.0
@@ -332,7 +346,7 @@ output:
332
346
  factors,
333
347
  multi_symbol_price_data,
334
348
  {},
335
- list(multi_symbol_price_data.keys())
349
+ list(multi_symbol_price_data.keys()),
336
350
  )
337
351
 
338
352
  assert "close_price" in factor_df.columns
@@ -345,6 +359,7 @@ output:
345
359
  assert len(result) == len(multi_symbol_price_data)
346
360
  finally:
347
361
  import os
362
+
348
363
  os.unlink(config_path)
349
364
 
350
365
  def test_filter_with_conditions(self, tmp_path, multi_symbol_price_data):
@@ -352,7 +367,7 @@ output:
352
367
  from quantcli.factors.compute import FactorComputer
353
368
  from quantcli.factors.ranking import ScoringEngine
354
369
 
355
- with tempfile.NamedTemporaryFile(mode='w', suffix='.yaml', delete=False) as f:
370
+ with tempfile.NamedTemporaryFile(mode="w", suffix=".yaml", delete=False) as f:
356
371
  f.write("""
357
372
  name: 测试条件筛选
358
373
  version: 1.0.0
@@ -387,7 +402,7 @@ output:
387
402
  factors,
388
403
  multi_symbol_price_data,
389
404
  {},
390
- list(multi_symbol_price_data.keys())
405
+ list(multi_symbol_price_data.keys()),
391
406
  )
392
407
 
393
408
  scorer = ScoringEngine(normalize="zscore")
@@ -397,6 +412,7 @@ output:
397
412
  assert "score" in result.columns
398
413
  finally:
399
414
  import os
415
+
400
416
  os.unlink(config_path)
401
417
 
402
418
  def test_filter_json_output_format(self, tmp_path, multi_symbol_price_data):
@@ -406,7 +422,7 @@ output:
406
422
  from quantcli.factors.compute import FactorComputer
407
423
  from quantcli.factors.ranking import ScoringEngine
408
424
 
409
- with tempfile.NamedTemporaryFile(mode='w', suffix='.yaml', delete=False) as f:
425
+ with tempfile.NamedTemporaryFile(mode="w", suffix=".yaml", delete=False) as f:
410
426
  f.write("""
411
427
  name: 测试策略
412
428
  version: 1.0.0
@@ -435,7 +451,7 @@ output:
435
451
  factors,
436
452
  multi_symbol_price_data,
437
453
  {},
438
- list(multi_symbol_price_data.keys())
454
+ list(multi_symbol_price_data.keys()),
439
455
  )
440
456
 
441
457
  scorer = ScoringEngine(normalize="zscore")
@@ -445,7 +461,7 @@ output:
445
461
  output = {
446
462
  "status": "success",
447
463
  "count": len(result),
448
- "results": result.to_dict(orient="records")
464
+ "results": result.to_dict(orient="records"),
449
465
  }
450
466
 
451
467
  assert output["status"] == "success"
@@ -454,6 +470,7 @@ output:
454
470
  assert len(parsed) > 0
455
471
  finally:
456
472
  import os
473
+
457
474
  os.unlink(config_path)
458
475
 
459
476
 
@@ -712,17 +729,22 @@ class TestFormulaSyntax:
712
729
  computer = FactorComputer()
713
730
 
714
731
  factors = {
715
- "ma20": FactorDefinition(name="ma20", type="technical", expr="ma(close, 20)"),
716
- "ema12": FactorDefinition(name="ema12", type="technical", expr="ema(close, 12)"),
717
- "delay5": FactorDefinition(name="delay5", type="technical", expr="delay(close, 5)"),
718
- "std20": FactorDefinition(name="std20", type="technical", expr="rolling_std(close, 20)"),
732
+ "ma20": FactorDefinition(
733
+ name="ma20", type="technical", expr="ma(close, 20)"
734
+ ),
735
+ "ema12": FactorDefinition(
736
+ name="ema12", type="technical", expr="ema(close, 12)"
737
+ ),
738
+ "delay5": FactorDefinition(
739
+ name="delay5", type="technical", expr="delay(close, 5)"
740
+ ),
741
+ "std20": FactorDefinition(
742
+ name="std20", type="technical", expr="rolling_std(close, 20)"
743
+ ),
719
744
  }
720
745
 
721
746
  result = computer.compute_all_factors(
722
- factors,
723
- {"600519": sample_price_data},
724
- {},
725
- ["600519"]
747
+ factors, {"600519": sample_price_data}, {}, ["600519"]
726
748
  )
727
749
 
728
750
  assert "ma20" in result.columns
@@ -739,14 +761,13 @@ class TestFormulaSyntax:
739
761
 
740
762
  factors = {
741
763
  "rank": FactorDefinition(name="rank", type="technical", expr="rank(close)"),
742
- "zscore": FactorDefinition(name="zscore", type="technical", expr="zscore(close)"),
764
+ "zscore": FactorDefinition(
765
+ name="zscore", type="technical", expr="zscore(close)"
766
+ ),
743
767
  }
744
768
 
745
769
  result = computer.compute_all_factors(
746
- factors,
747
- {"600519": sample_price_data},
748
- {},
749
- ["600519"]
770
+ factors, {"600519": sample_price_data}, {}, ["600519"]
750
771
  )
751
772
 
752
773
  assert "rank" in result.columns
@@ -761,14 +782,13 @@ class TestFormulaSyntax:
761
782
 
762
783
  # correlation 计算 - 价格与成交量的相关性
763
784
  factors = {
764
- "corr": FactorDefinition(name="corr", type="technical", expr="correlation(close, volume, 10)"),
785
+ "corr": FactorDefinition(
786
+ name="corr", type="technical", expr="correlation(close, volume, 10)"
787
+ ),
765
788
  }
766
789
 
767
790
  result = computer.compute_all_factors(
768
- factors,
769
- {"600519": sample_price_data},
770
- {},
771
- ["600519"]
791
+ factors, {"600519": sample_price_data}, {}, ["600519"]
772
792
  )
773
793
 
774
794
  assert "corr" in result.columns
@@ -781,15 +801,16 @@ class TestFormulaSyntax:
781
801
  computer = FactorComputer()
782
802
 
783
803
  factors = {
784
- "is_up": FactorDefinition(name="is_up", type="technical", expr="where(close > open, 1, 0)"),
785
- "is_yinliang": FactorDefinition(name="is_yinliang", type="technical", expr="where(close < open, 1, 0)"),
804
+ "is_up": FactorDefinition(
805
+ name="is_up", type="technical", expr="where(close > open, 1, 0)"
806
+ ),
807
+ "is_yinliang": FactorDefinition(
808
+ name="is_yinliang", type="technical", expr="where(close < open, 1, 0)"
809
+ ),
786
810
  }
787
811
 
788
812
  result = computer.compute_all_factors(
789
- factors,
790
- {"600519": sample_price_data},
791
- {},
792
- ["600519"]
813
+ factors, {"600519": sample_price_data}, {}, ["600519"]
793
814
  )
794
815
 
795
816
  assert "is_up" in result.columns
File without changes
File without changes
File without changes
File without changes
File without changes