xtquant-duck 0.1.20260702.2__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.
@@ -0,0 +1,25 @@
1
+ .venv/
2
+ __pycache__/
3
+ *.py[cod]
4
+ *.pyo
5
+ *.pyd
6
+ *.egg-info/
7
+ dist/
8
+ build/
9
+ .pytest_cache/
10
+ .mypy_cache/
11
+ .ruff_cache/
12
+ .coverage
13
+ htmlcov/
14
+
15
+ reports/
16
+ *.duckdb
17
+ *.duckdb.wal
18
+ *.parquet
19
+ *.csv
20
+ *.log
21
+ *.tmp
22
+
23
+ .env
24
+ .env.*
25
+ !.env.example
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 drunkpig
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,93 @@
1
+ Metadata-Version: 2.4
2
+ Name: xtquant-duck
3
+ Version: 0.1.20260702.2
4
+ Summary: DuckDB-backed local mock implementation of selected xtquant APIs.
5
+ Project-URL: Homepage, https://github.com/drunkpig/xtquant-duck
6
+ Project-URL: Repository, https://github.com/drunkpig/xtquant-duck
7
+ Project-URL: Issues, https://github.com/drunkpig/xtquant-duck/issues
8
+ Author: drunkpig
9
+ License: MIT
10
+ License-File: LICENSE
11
+ Keywords: duckdb,mock,qmt,quant,xtquant
12
+ Classifier: Development Status :: 3 - Alpha
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: License :: OSI Approved :: MIT License
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3.10
17
+ Classifier: Programming Language :: Python :: 3.11
18
+ Classifier: Programming Language :: Python :: 3.12
19
+ Requires-Python: >=3.10
20
+ Requires-Dist: duckdb>=1.0
21
+ Requires-Dist: numpy>=1.24
22
+ Requires-Dist: pandas>=2.0
23
+ Requires-Dist: pyarrow>=14.0
24
+ Description-Content-Type: text/markdown
25
+
26
+ # xtquant-duck
27
+
28
+ DuckDB-backed local mock implementation of selected `xtquant` APIs.
29
+
30
+ The goal is to let research code switch between real QMT `xtquant.xtdata` and a
31
+ local DuckDB-backed mock without changing strategy logic. QMT semantics are the
32
+ canonical reference; unsupported mock behavior raises `NotImplementedError`
33
+ instead of silently returning placeholder data.
34
+
35
+ ## Install
36
+
37
+ ```powershell
38
+ uv pip install xtquant-duck
39
+ ```
40
+
41
+ For local development:
42
+
43
+ ```powershell
44
+ git clone git@github.com:drunkpig/xtquant-duck.git
45
+ cd xtquant-duck
46
+ uv sync --all-extras --dev
47
+ ```
48
+
49
+ ## Basic Usage
50
+
51
+ Set the DuckDB database path:
52
+
53
+ ```powershell
54
+ $env:QMT_MOCK_DUCKDB = "C:\data-tick\duckdb\qmt_mock.duckdb"
55
+ ```
56
+
57
+ Use the mock `xtquant` package directly:
58
+
59
+ ```python
60
+ from xtquant import xtdata
61
+
62
+ data = xtdata.get_market_data_ex(
63
+ field_list=["time", "open", "high", "low", "close", "volume"],
64
+ stock_list=["600036.SH"],
65
+ period="1d",
66
+ start_time="20220101",
67
+ end_time="20251231",
68
+ dividend_type="back_ratio",
69
+ )
70
+ ```
71
+
72
+ Lower-level DuckDB access is available through:
73
+
74
+ ```python
75
+ from qmt_data_layer import DuckDbMarketData
76
+ ```
77
+
78
+ Default database path is `C:\data-tick\duckdb\qmt_mock.duckdb`; override it with
79
+ `QMT_MOCK_DUCKDB`.
80
+
81
+ ## Documentation
82
+
83
+ See [docs/MOCK_XTQUANT_API.md](docs/MOCK_XTQUANT_API.md) for supported APIs,
84
+ parameters, return shapes, and strict unsupported behavior.
85
+
86
+ ## Tests
87
+
88
+ ```powershell
89
+ uv run python -m unittest discover -s test -v
90
+ ```
91
+
92
+ The unit tests build a temporary DuckDB database and do not read or write the
93
+ default production database.
@@ -0,0 +1,68 @@
1
+ # xtquant-duck
2
+
3
+ DuckDB-backed local mock implementation of selected `xtquant` APIs.
4
+
5
+ The goal is to let research code switch between real QMT `xtquant.xtdata` and a
6
+ local DuckDB-backed mock without changing strategy logic. QMT semantics are the
7
+ canonical reference; unsupported mock behavior raises `NotImplementedError`
8
+ instead of silently returning placeholder data.
9
+
10
+ ## Install
11
+
12
+ ```powershell
13
+ uv pip install xtquant-duck
14
+ ```
15
+
16
+ For local development:
17
+
18
+ ```powershell
19
+ git clone git@github.com:drunkpig/xtquant-duck.git
20
+ cd xtquant-duck
21
+ uv sync --all-extras --dev
22
+ ```
23
+
24
+ ## Basic Usage
25
+
26
+ Set the DuckDB database path:
27
+
28
+ ```powershell
29
+ $env:QMT_MOCK_DUCKDB = "C:\data-tick\duckdb\qmt_mock.duckdb"
30
+ ```
31
+
32
+ Use the mock `xtquant` package directly:
33
+
34
+ ```python
35
+ from xtquant import xtdata
36
+
37
+ data = xtdata.get_market_data_ex(
38
+ field_list=["time", "open", "high", "low", "close", "volume"],
39
+ stock_list=["600036.SH"],
40
+ period="1d",
41
+ start_time="20220101",
42
+ end_time="20251231",
43
+ dividend_type="back_ratio",
44
+ )
45
+ ```
46
+
47
+ Lower-level DuckDB access is available through:
48
+
49
+ ```python
50
+ from qmt_data_layer import DuckDbMarketData
51
+ ```
52
+
53
+ Default database path is `C:\data-tick\duckdb\qmt_mock.duckdb`; override it with
54
+ `QMT_MOCK_DUCKDB`.
55
+
56
+ ## Documentation
57
+
58
+ See [docs/MOCK_XTQUANT_API.md](docs/MOCK_XTQUANT_API.md) for supported APIs,
59
+ parameters, return shapes, and strict unsupported behavior.
60
+
61
+ ## Tests
62
+
63
+ ```powershell
64
+ uv run python -m unittest discover -s test -v
65
+ ```
66
+
67
+ The unit tests build a temporary DuckDB database and do not read or write the
68
+ default production database.
@@ -0,0 +1,310 @@
1
+ # Mock xtquant API
2
+
3
+ This document describes the DuckDB-backed mock package installed as:
4
+
5
+ `xtquant`
6
+
7
+ Install `xtquant-duck` or place `C:\workspace\xtquant-duck` before the real QMT package on `PYTHONPATH`.
8
+
9
+ The mock is intentionally strict. Unsupported semantics raise `NotImplementedError`; missing local data raises `FileNotFoundError`. It must not silently return placeholder market data.
10
+
11
+ ## Environment
12
+
13
+ | variable | default | meaning |
14
+ | --- | --- | --- |
15
+ | `QMT_MOCK_DUCKDB` | `C:\data-tick\duckdb\qmt_mock.duckdb` | DuckDB database path |
16
+ | `QMT_MOCK_NOW` | current local time | default clock for `get_full_tick` if `set_mock_now()` is not used |
17
+
18
+ ## Time And Code Rules
19
+
20
+ Stock codes are normalized to QMT format, for example:
21
+
22
+ - `sh600000` -> `600000.SH`
23
+ - `600000.SH` -> `600000.SH`
24
+ - `000001` -> `000001.SZ`
25
+
26
+ Time parameters accept the formats handled by `parse_qmt_time()`:
27
+
28
+ - `YYYYMMDD`
29
+ - `YYYYMMDDHHMMSS`
30
+ - pandas-compatible datetime strings
31
+ - Unix seconds or milliseconds as integers
32
+
33
+ Returned `time` values use QMT-style local-time milliseconds since Unix epoch.
34
+
35
+ ## `xtquant.xtdata`
36
+
37
+ ### `download_history_data(stock_code, period, start_time="", end_time="", incrementally=False, **kwargs) -> bool`
38
+
39
+ Validates that local DuckDB already has data for the requested code, period, and time range.
40
+
41
+ Supported parameters:
42
+
43
+ | parameter | supported value |
44
+ | --- | --- |
45
+ | `stock_code` | QMT-style or normalizable stock code |
46
+ | `period` | `tick`, `1m`, `1min`, `60m`, `60min`, `1h`, `1d`, `day`, `d` |
47
+ | `start_time`, `end_time` | optional QMT-style time strings |
48
+ | `incrementally` | only `False` |
49
+
50
+ Returns `True` when local data exists.
51
+
52
+ Raises:
53
+
54
+ - `FileNotFoundError` if DuckDB has no matching local data.
55
+ - `NotImplementedError` for unsupported period, `incrementally=True`, or extra keyword arguments.
56
+
57
+ ### `download_history_data2(stock_list, period, start_time="", end_time="", incrementally=False, **kwargs) -> bool`
58
+
59
+ Calls `download_history_data()` for every stock in `stock_list`.
60
+
61
+ Returns `True` only when every stock has matching local data.
62
+
63
+ Raises the same exceptions as `download_history_data()`.
64
+
65
+ ### `get_market_data_ex(field_list=None, stock_list=None, period="1d", start_time="", end_time="", count=-1, fill_data=False, dividend_type=None, **kwargs) -> dict[str, pandas.DataFrame]`
66
+
67
+ Main historical market-data API.
68
+
69
+ Supported parameters:
70
+
71
+ | parameter | supported value |
72
+ | --- | --- |
73
+ | `field_list` | `None`, empty list, or implemented field names for the requested period |
74
+ | `stock_list` | list of QMT-style or normalizable stock codes |
75
+ | `period` | `tick`, `1m`, `1min`, `60m`, `60min`, `1h`, `1d`, `day`, `d` |
76
+ | `start_time`, `end_time` | optional QMT-style time strings |
77
+ | `count` | `-1`/`0` for all rows, positive integer for tail rows |
78
+ | `fill_data` | only `False` |
79
+ | `dividend_type` | see period-specific rules below |
80
+
81
+ Return value is a dict keyed by normalized QMT code. Each value is a pandas DataFrame sorted by time.
82
+
83
+ When `field_list` is provided, only those fields are returned. If the DataFrame has a `time` column and `time` was not requested, `time` is still prepended to match strategy expectations. Requesting an unimplemented field raises `NotImplementedError`.
84
+
85
+ #### Period `tick`
86
+
87
+ Source: `raw_tick_v3`.
88
+
89
+ Price domain: raw, never adjusted.
90
+
91
+ Supported `dividend_type`: `None`, `""`, `none`.
92
+
93
+ Fields:
94
+
95
+ | field | meaning |
96
+ | --- | --- |
97
+ | `time` | QMT-style millisecond timestamp |
98
+ | `ts` | pandas timestamp |
99
+ | `lastPrice` | latest raw tick price |
100
+ | `volume` | cumulative trading-day volume in lots up to this tick |
101
+ | `amount` | cumulative trading-day amount up to this tick |
102
+ | `open` | first valid tick price of the trading day up to this tick |
103
+ | `askPrice`, `bidPrice` | 5-level price lists |
104
+ | `askVol`, `bidVol` | 5-level volume lists |
105
+
106
+ `dividend_type` other than empty/`none` raises `NotImplementedError`.
107
+
108
+ #### Period `1m` / `1min`
109
+
110
+ Source: dynamic aggregation from `raw_tick_v3`.
111
+
112
+ Raw bar rules:
113
+
114
+ - `09:30` bar is the opening auction bar from `09:25` ticks.
115
+ - Continuous auction bars are right-labeled.
116
+ - `15:00` closing auction tick is labeled `15:00`.
117
+ - `volume` is per-bar volume in lots.
118
+ - `amount` is per-bar traded amount.
119
+
120
+ Supported `dividend_type`:
121
+
122
+ | value | behavior |
123
+ | --- | --- |
124
+ | `None`, `""`, `none` | raw 1m bars |
125
+ | `front_ratio`, `front` | dynamic front-adjusted 1m bars |
126
+
127
+ Base fields:
128
+
129
+ | field | meaning |
130
+ | --- | --- |
131
+ | `time`, `ts` | bar label time |
132
+ | `open`, `high`, `low`, `close` | raw or front-adjusted price depending on `dividend_type` |
133
+ | `volume`, `amount` | raw per-bar volume/amount, not adjusted |
134
+ | `preClose` | currently `NaN` for raw intraday bars |
135
+
136
+ Additional fields for `front_ratio`/`front`:
137
+
138
+ | field | meaning |
139
+ | --- | --- |
140
+ | `raw_open`, `raw_high`, `raw_low`, `raw_close`, `raw_preClose` | raw price fields before adjustment |
141
+ | `foreAdjustFactor` | BaoStock factor as of the bar date |
142
+ | `anchor_factor` | BaoStock factor as of the latest bar date in the requested result set |
143
+
144
+ Formula:
145
+
146
+ `adjusted_price = raw_price * foreAdjustFactor(bar_date) / foreAdjustFactor(anchor_date)`
147
+
148
+ `back_ratio`/`back` raises `NotImplementedError`.
149
+
150
+ #### Period `60m` / `60min` / `1h`
151
+
152
+ Source: dynamic aggregation from `raw_tick_v3`, not from 1m bars.
153
+
154
+ Raw bar boundaries:
155
+
156
+ - `10:30`: `[09:30, 10:30)`
157
+ - `11:30`: `[10:30, 11:30)`
158
+ - `14:00`: `[13:00, 14:00)`
159
+ - `15:00`: `[14:00, 15:00:59]`
160
+
161
+ Fields and `dividend_type` behavior are the same as `1m`.
162
+
163
+ The current strategy requests raw 60m bars.
164
+
165
+ #### Period `1d` / `day` / `d`
166
+
167
+ Source: `raw_daily_v1`.
168
+
169
+ Supported `dividend_type`:
170
+
171
+ | value | behavior |
172
+ | --- | --- |
173
+ | `None`, `""`, `none` | raw daily bars |
174
+ | `front_ratio`, `front` | dynamic front-adjusted daily bars |
175
+ | `back_ratio`, `back` | BaoStock back-adjusted daily bars |
176
+
177
+ Raw fields:
178
+
179
+ | field | meaning |
180
+ | --- | --- |
181
+ | `time`, `ts` | trading date |
182
+ | `open`, `high`, `low`, `close` | raw OHLC |
183
+ | `volume` | daily volume in lots |
184
+ | `amount` | daily traded amount |
185
+ | `preClose` | previous raw close within the returned source sequence |
186
+
187
+ Additional fields for `front_ratio`/`front`:
188
+
189
+ | field | meaning |
190
+ | --- | --- |
191
+ | `raw_open`, `raw_high`, `raw_low`, `raw_close`, `raw_preClose` | raw daily fields before adjustment |
192
+ | `foreAdjustFactor` | BaoStock factor as of the trading date |
193
+ | `anchor_factor` | BaoStock factor as of the latest trading date in the requested result set |
194
+
195
+ Formula:
196
+
197
+ `adjusted_price = raw_price * foreAdjustFactor(date) / foreAdjustFactor(anchor_date)`
198
+
199
+ Additional fields for `back_ratio`/`back`:
200
+
201
+ | field | meaning |
202
+ | --- | --- |
203
+ | `raw_open`, `raw_high`, `raw_low`, `raw_close`, `raw_preClose` | raw daily fields before adjustment |
204
+ | `backAdjustFactor` | BaoStock back-adjust factor as of the trading date |
205
+
206
+ Formula:
207
+
208
+ `adjusted_price = raw_price * backAdjustFactor(date)`
209
+
210
+ ### `get_full_tick(stock_list) -> dict[str, dict]`
211
+
212
+ Returns the latest raw tick for each stock at the mock clock.
213
+
214
+ Clock source:
215
+
216
+ 1. `set_mock_now(value)` if called.
217
+ 2. `QMT_MOCK_NOW` environment variable.
218
+ 3. current local time.
219
+
220
+ Returned dict fields match the tick fields used by the strategy:
221
+
222
+ | field | meaning |
223
+ | --- | --- |
224
+ | `time`, `ts` | tick time |
225
+ | `lastPrice` | latest raw tick price |
226
+ | `volume` | cumulative trading-day volume in lots up to the tick |
227
+ | `amount` | cumulative trading-day amount up to the tick |
228
+ | `open` | first valid tick price of the trading day up to the tick |
229
+ | `askPrice`, `bidPrice`, `askVol`, `bidVol` | 5-level lists |
230
+
231
+ Stocks with no tick at or before the mock clock for that day are omitted from the returned dict.
232
+
233
+ ### `set_mock_now(value) -> None`
234
+
235
+ Sets the process-local mock clock used by `get_full_tick()`.
236
+
237
+ ### `get_mock_now() -> pandas.Timestamp | None`
238
+
239
+ Returns the process-local mock clock, or `None` if unset.
240
+
241
+ ### `close() -> None`
242
+
243
+ Closes the cached DuckDB connection used by the mock module.
244
+
245
+ ### Unsupported push APIs
246
+
247
+ These APIs are declared only so imports resolve, but push subscriptions are not implemented:
248
+
249
+ - `subscribe_quote(...)`
250
+ - `subscribe_whole_quote(...)`
251
+ - `unsubscribe_quote(...)`
252
+ - `run()`
253
+
254
+ All raise `NotImplementedError`.
255
+
256
+ ## `xtquant.xttrader`
257
+
258
+ The mock package provides import-compatible stubs:
259
+
260
+ - `XtQuantTraderCallback`
261
+ - `XtQuantTrader`
262
+
263
+ `XtQuantTrader.register_callback(callback)` stores the callback object only.
264
+
265
+ The following trading/account methods are not implemented and raise `NotImplementedError`:
266
+
267
+ - `start()`
268
+ - `connect()`
269
+ - `subscribe(account)`
270
+ - `query_stock_asset(account)`
271
+ - `query_stock_positions(account)`
272
+ - `query_stock_orders(account, cancelable_only=False)`
273
+ - `query_stock_trades(account)`
274
+
275
+ This prevents mock backtests from accidentally treating placeholder account data as real trading state.
276
+
277
+ ## `xtquant.xttype`
278
+
279
+ ### `StockAccount(account_id: str, account_type: str = "STOCK")`
280
+
281
+ Simple data holder with attributes:
282
+
283
+ - `account_id`
284
+ - `account_type`
285
+
286
+ ## `xtquant.xtconstant`
287
+
288
+ Defined constants:
289
+
290
+ | name | value |
291
+ | --- | --- |
292
+ | `STOCK_BUY` | `23` |
293
+ | `STOCK_SELL` | `24` |
294
+ | `FIX_PRICE` | `11` |
295
+ | `LATEST_PRICE` | `5` |
296
+
297
+ ## Tests
298
+
299
+ Run:
300
+
301
+ ```powershell
302
+ uv run python -m unittest discover -s test -v
303
+ ```
304
+
305
+ The tests build a temporary DuckDB database and verify:
306
+
307
+ - raw tick cumulative fields.
308
+ - dynamic front-adjusted 1m and daily data.
309
+ - strict `NotImplementedError` behavior.
310
+ - mock `download_history_data`, `get_market_data_ex`, `get_full_tick`, and trader stubs.
@@ -0,0 +1,55 @@
1
+ [project]
2
+ name = "xtquant-duck"
3
+ version = "0.1.20260702.2"
4
+ description = "DuckDB-backed local mock implementation of selected xtquant APIs."
5
+ readme = "README.md"
6
+ requires-python = ">=3.10"
7
+ license = { text = "MIT" }
8
+ authors = [
9
+ { name = "drunkpig" }
10
+ ]
11
+ keywords = ["xtquant", "qmt", "duckdb", "quant", "mock"]
12
+ classifiers = [
13
+ "Development Status :: 3 - Alpha",
14
+ "Intended Audience :: Developers",
15
+ "License :: OSI Approved :: MIT License",
16
+ "Programming Language :: Python :: 3",
17
+ "Programming Language :: Python :: 3.10",
18
+ "Programming Language :: Python :: 3.11",
19
+ "Programming Language :: Python :: 3.12",
20
+ ]
21
+ dependencies = [
22
+ "duckdb>=1.0",
23
+ "numpy>=1.24",
24
+ "pandas>=2.0",
25
+ "pyarrow>=14.0",
26
+ ]
27
+
28
+ [project.urls]
29
+ Homepage = "https://github.com/drunkpig/xtquant-duck"
30
+ Repository = "https://github.com/drunkpig/xtquant-duck"
31
+ Issues = "https://github.com/drunkpig/xtquant-duck/issues"
32
+
33
+ [dependency-groups]
34
+ dev = [
35
+ "build>=1.2",
36
+ ]
37
+
38
+ [build-system]
39
+ requires = ["hatchling>=1.25"]
40
+ build-backend = "hatchling.build"
41
+
42
+ [tool.hatch.build.targets.wheel]
43
+ packages = ["qmt_data_layer", "xtquant"]
44
+
45
+ [tool.hatch.build.targets.sdist]
46
+ include = [
47
+ "qmt_data_layer",
48
+ "xtquant",
49
+ "scripts",
50
+ "docs",
51
+ "test",
52
+ "README.md",
53
+ "LICENSE",
54
+ "pyproject.toml",
55
+ ]
@@ -0,0 +1,5 @@
1
+ """DuckDB-backed local market data layer for QMT-compatible research."""
2
+
3
+ from .duckdb_data import DuckDbMarketData
4
+
5
+ __all__ = ["DuckDbMarketData"]