qka 1.6.5.dev5__tar.gz → 1.7.1.dev2__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 (63) hide show
  1. {qka-1.6.5.dev5 → qka-1.7.1.dev2}/PKG-INFO +1 -1
  2. {qka-1.6.5.dev5 → qka-1.7.1.dev2}/qka/core/data.py +60 -23
  3. {qka-1.6.5.dev5 → qka-1.7.1.dev2}/.github/workflows/docs.yml +0 -0
  4. {qka-1.6.5.dev5 → qka-1.7.1.dev2}/.github/workflows/release.yml +0 -0
  5. {qka-1.6.5.dev5 → qka-1.7.1.dev2}/.gitignore +0 -0
  6. {qka-1.6.5.dev5 → qka-1.7.1.dev2}/.vscode/settings.json +0 -0
  7. {qka-1.6.5.dev5 → qka-1.7.1.dev2}/CHANGELOG.md +0 -0
  8. {qka-1.6.5.dev5 → qka-1.7.1.dev2}/LICENSE +0 -0
  9. {qka-1.6.5.dev5 → qka-1.7.1.dev2}/README.md +0 -0
  10. {qka-1.6.5.dev5 → qka-1.7.1.dev2}/docs/advanced/performance.md +0 -0
  11. {qka-1.6.5.dev5 → qka-1.7.1.dev2}/docs/api/brokers.md +0 -0
  12. {qka-1.6.5.dev5 → qka-1.7.1.dev2}/docs/api/core.md +0 -0
  13. {qka-1.6.5.dev5 → qka-1.7.1.dev2}/docs/api/utils.md +0 -0
  14. {qka-1.6.5.dev5 → qka-1.7.1.dev2}/docs/examples/buy_and_hold.md +0 -0
  15. {qka-1.6.5.dev5 → qka-1.7.1.dev2}/docs/examples/ma_cross.md +0 -0
  16. {qka-1.6.5.dev5 → qka-1.7.1.dev2}/docs/examples/momentum.md +0 -0
  17. {qka-1.6.5.dev5 → qka-1.7.1.dev2}/docs/examples/multi_factor.md +0 -0
  18. {qka-1.6.5.dev5 → qka-1.7.1.dev2}/docs/examples/rsi_atr.md +0 -0
  19. {qka-1.6.5.dev5 → qka-1.7.1.dev2}/docs/guides/backtest.md +0 -0
  20. {qka-1.6.5.dev5 → qka-1.7.1.dev2}/docs/guides/data.md +0 -0
  21. {qka-1.6.5.dev5 → qka-1.7.1.dev2}/docs/guides/indicators.md +0 -0
  22. {qka-1.6.5.dev5 → qka-1.7.1.dev2}/docs/guides/report.md +0 -0
  23. {qka-1.6.5.dev5 → qka-1.7.1.dev2}/docs/guides/sizing.md +0 -0
  24. {qka-1.6.5.dev5 → qka-1.7.1.dev2}/docs/guides/strategy.md +0 -0
  25. {qka-1.6.5.dev5 → qka-1.7.1.dev2}/docs/guides/trading.md +0 -0
  26. {qka-1.6.5.dev5 → qka-1.7.1.dev2}/docs/index.md +0 -0
  27. {qka-1.6.5.dev5 → qka-1.7.1.dev2}/docs/user-guide/trading.md +0 -0
  28. {qka-1.6.5.dev5 → qka-1.7.1.dev2}/mkdocs.yml +0 -0
  29. {qka-1.6.5.dev5 → qka-1.7.1.dev2}/pyproject.toml +0 -0
  30. {qka-1.6.5.dev5 → qka-1.7.1.dev2}/qka/__init__.py +0 -0
  31. {qka-1.6.5.dev5 → qka-1.7.1.dev2}/qka/brokers/__init__.py +0 -0
  32. {qka-1.6.5.dev5 → qka-1.7.1.dev2}/qka/brokers/client.py +0 -0
  33. {qka-1.6.5.dev5 → qka-1.7.1.dev2}/qka/brokers/server.py +0 -0
  34. {qka-1.6.5.dev5 → qka-1.7.1.dev2}/qka/brokers/trade.py +0 -0
  35. {qka-1.6.5.dev5 → qka-1.7.1.dev2}/qka/cli.py +0 -0
  36. {qka-1.6.5.dev5 → qka-1.7.1.dev2}/qka/core/__init__.py +0 -0
  37. {qka-1.6.5.dev5 → qka-1.7.1.dev2}/qka/core/accessor.py +0 -0
  38. {qka-1.6.5.dev5 → qka-1.7.1.dev2}/qka/core/backtest.py +0 -0
  39. {qka-1.6.5.dev5 → qka-1.7.1.dev2}/qka/core/broker.py +0 -0
  40. {qka-1.6.5.dev5 → qka-1.7.1.dev2}/qka/core/report.py +0 -0
  41. {qka-1.6.5.dev5 → qka-1.7.1.dev2}/qka/core/sizing.py +0 -0
  42. {qka-1.6.5.dev5 → qka-1.7.1.dev2}/qka/core/strategy.py +0 -0
  43. {qka-1.6.5.dev5 → qka-1.7.1.dev2}/qka/mcp/__init__.py +0 -0
  44. {qka-1.6.5.dev5 → qka-1.7.1.dev2}/qka/mcp/api.py +0 -0
  45. {qka-1.6.5.dev5 → qka-1.7.1.dev2}/qka/mcp/server.py +0 -0
  46. {qka-1.6.5.dev5 → qka-1.7.1.dev2}/qka/server/__init__.py +0 -0
  47. {qka-1.6.5.dev5 → qka-1.7.1.dev2}/qka/server/handlers/__init__.py +0 -0
  48. {qka-1.6.5.dev5 → qka-1.7.1.dev2}/qka/server/handlers/class_inspector_handler.py +0 -0
  49. {qka-1.6.5.dev5 → qka-1.7.1.dev2}/qka/server/handlers/code_executor_handler.py +0 -0
  50. {qka-1.6.5.dev5 → qka-1.7.1.dev2}/qka/server/ws_client.py +0 -0
  51. {qka-1.6.5.dev5 → qka-1.7.1.dev2}/qka/server/zmq_server.py +0 -0
  52. {qka-1.6.5.dev5 → qka-1.7.1.dev2}/qka/utils/__init__.py +0 -0
  53. {qka-1.6.5.dev5 → qka-1.7.1.dev2}/qka/utils/anis.py +0 -0
  54. {qka-1.6.5.dev5 → qka-1.7.1.dev2}/qka/utils/logger.py +0 -0
  55. {qka-1.6.5.dev5 → qka-1.7.1.dev2}/qka/utils/util.py +0 -0
  56. {qka-1.6.5.dev5 → qka-1.7.1.dev2}/skills/qka/SKILL.md +0 -0
  57. {qka-1.6.5.dev5 → qka-1.7.1.dev2}/skills/qka/references/backtest.md +0 -0
  58. {qka-1.6.5.dev5 → qka-1.7.1.dev2}/skills/qka/references/broker.md +0 -0
  59. {qka-1.6.5.dev5 → qka-1.7.1.dev2}/skills/qka/references/data.md +0 -0
  60. {qka-1.6.5.dev5 → qka-1.7.1.dev2}/skills/qka/references/report.md +0 -0
  61. {qka-1.6.5.dev5 → qka-1.7.1.dev2}/skills/qka/references/sizing.md +0 -0
  62. {qka-1.6.5.dev5 → qka-1.7.1.dev2}/skills/qka/references/strategy.md +0 -0
  63. {qka-1.6.5.dev5 → qka-1.7.1.dev2}/tools/generate_api_ref.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: qka
3
- Version: 1.6.5.dev5
3
+ Version: 1.7.1.dev2
4
4
  Summary: QKA(快量化 / Quant Kit for A-shares)- 简洁易用的 A 股量化回测框架
5
5
  Project-URL: Home, https://github.com/zsrl/qka
6
6
  Project-URL: Documentation, https://zsrl.github.io/qka
@@ -108,32 +108,63 @@ class Data():
108
108
 
109
109
  def _download(self, symbol: str) -> Path:
110
110
  """
111
- 下载单个股票的数据
112
-
111
+ 下载或更新单个股票的数据。
112
+
113
+ 首次下载全量数据。已存在时只增量拉取最新数据(从 parquet 最后日期到今日),
114
+ 追加合并后重新写入,确保缓存始终保持最新。
115
+
113
116
  Args:
114
- symbol (str): 股票代码
115
-
117
+ symbol: 股票代码
118
+
116
119
  Returns:
117
120
  Path: 数据文件路径
121
+
122
+ Raises:
123
+ RuntimeError: 数据源返回空数据(首次下载时)
118
124
  """
119
125
  path = self.target_dir / f"{symbol}.parquet"
120
126
 
121
- if path.exists():
122
- return path
123
-
124
- if self.source == 'akshare':
125
- df = self._get_from_akshare(symbol)
126
- elif self.source == 'baostock':
127
- df = self._get_from_baostock(symbol)
128
- else:
129
- df = pd.DataFrame()
130
-
131
- if len(df) == 0:
132
- raise RuntimeError(f"{symbol}: baostock 返回空数据")
133
-
134
- table = pa.Table.from_pandas(df)
127
+ # ── 首次下载:全量 ──
128
+ if not path.exists():
129
+ if self.source == 'akshare':
130
+ df = self._get_from_akshare(symbol)
131
+ elif self.source == 'baostock':
132
+ df = self._get_from_baostock(symbol)
133
+ else:
134
+ df = pd.DataFrame()
135
+
136
+ if len(df) == 0:
137
+ raise RuntimeError(f"{symbol}: baostock 返回空数据")
138
+ table = pa.Table.from_pandas(df)
139
+ pq.write_table(table, path)
140
+ return path
141
+
142
+ # ── 增量更新 ──
143
+ if self.source != 'baostock':
144
+ return path # 仅 baostock 支持增量
145
+
146
+ # 读已有数据的最后日期
147
+ existing = pd.read_parquet(path)
148
+ if not isinstance(existing.index, pd.DatetimeIndex):
149
+ return path # 非日期索引,跳过增量(保持原文件不变)
150
+ last_date = existing.index.max()
151
+ today_str = pd.Timestamp.now().strftime("%Y-%m-%d")
152
+ next_date = (last_date + pd.Timedelta(days=1)).strftime("%Y-%m-%d")
153
+
154
+ if next_date > today_str:
155
+ return path # 已是最新
156
+
157
+ df_new = self._get_from_baostock(symbol, start_date=next_date)
158
+ if len(df_new) == 0:
159
+ return path # 没有新数据(交易日还未到)
160
+
161
+ # 合并去重
162
+ combined = pd.concat([existing, df_new])
163
+ combined = combined[~combined.index.duplicated(keep='last')]
164
+ combined = combined.sort_index()
165
+
166
+ table = pa.Table.from_pandas(combined)
135
167
  pq.write_table(table, path)
136
-
137
168
  return path
138
169
 
139
170
  def get(self, lazy: bool = False):
@@ -459,12 +490,18 @@ class Data():
459
490
  # 设置索引
460
491
  return df
461
492
 
462
- def _get_from_baostock(self, symbol: str) -> pd.DataFrame:
493
+ def _get_from_baostock(
494
+ self, symbol: str,
495
+ start_date: str = '1990-01-01',
496
+ end_date: str = '2050-12-31',
497
+ ) -> pd.DataFrame:
463
498
  """
464
499
  从 baostock 获取单个股票的数据。
465
500
 
466
501
  Args:
467
- symbol (str): 股票代码,支持带后缀如 000001.SZ 或 600000.SH
502
+ symbol: 股票代码,支持带后缀如 000001.SZ 或 600000.SH
503
+ start_date: 起始日期,格式 YYYY-MM-DD,默认 1990-01-01
504
+ end_date: 截止日期,格式 YYYY-MM-DD,默认 2050-12-31
468
505
 
469
506
  Returns:
470
507
  pd.DataFrame: 股票数据,以 date 为索引,包含 open, high, low, close, volume, amount 列
@@ -481,8 +518,8 @@ class Data():
481
518
  rs = bs.query_history_k_data_plus(
482
519
  bs_code,
483
520
  "date,open,high,low,close,volume,amount",
484
- start_date='1990-01-01',
485
- end_date='2050-12-31',
521
+ start_date=start_date,
522
+ end_date=end_date,
486
523
  frequency='d',
487
524
  adjustflag=adjustflag,
488
525
  )
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes