1
1
2026-06-24 0f716e8836e66e6c220fcfb288d1a21a2153affc
1
5 files modified
84 files added
844 ■■■■■ changed files
.gitignore 1 ●●●● patch | view | raw | blame | history
data/result/stat/ds_minute_backfill_20260619/background.stderr.log 7 ●●●●● patch | view | raw | blame | history
data/result/stat/ds_minute_backfill_20260619/background.stdout.log patch | view | raw | blame | history
data/result/stat/ds_minute_backfill_20260619_r2/background.stderr.log patch | view | raw | blame | history
data/result/stat/ds_minute_backfill_20260619_r2/background.stdout.log patch | view | raw | blame | history
data/result/stat/ds_minute_backfill_20260619_r2/dates.txt 37 ●●●●● patch | view | raw | blame | history
data/result/stat/ds_minute_backfill_20260619_r2/ds_minute_sync_20260423_162049.err.txt patch | view | raw | blame | history
data/result/stat/ds_minute_backfill_20260619_r2/ds_minute_sync_20260423_162049.out.json patch | view | raw | blame | history
data/result/stat/ds_minute_backfill_20260619_r2/ds_minute_sync_20260424_162709.err.txt patch | view | raw | blame | history
data/result/stat/ds_minute_backfill_20260619_r2/ds_minute_sync_20260424_162709.out.json patch | view | raw | blame | history
data/result/stat/ds_minute_backfill_20260619_r2/ds_minute_sync_20260427_163323.err.txt patch | view | raw | blame | history
data/result/stat/ds_minute_backfill_20260619_r2/ds_minute_sync_20260427_163323.out.json patch | view | raw | blame | history
data/result/stat/ds_minute_backfill_20260619_r2/ds_minute_sync_20260428_163932.err.txt patch | view | raw | blame | history
data/result/stat/ds_minute_backfill_20260619_r2/ds_minute_sync_20260428_163932.out.json patch | view | raw | blame | history
data/result/stat/ds_minute_backfill_20260619_r2/ds_minute_sync_20260429_164538.err.txt patch | view | raw | blame | history
data/result/stat/ds_minute_backfill_20260619_r2/ds_minute_sync_20260429_164538.out.json patch | view | raw | blame | history
data/result/stat/ds_minute_backfill_20260619_r2/ds_minute_sync_20260430_165136.err.txt patch | view | raw | blame | history
data/result/stat/ds_minute_backfill_20260619_r2/ds_minute_sync_20260430_165136.out.json patch | view | raw | blame | history
data/result/stat/ds_minute_backfill_20260619_r2/ds_minute_sync_20260506_165739.err.txt patch | view | raw | blame | history
data/result/stat/ds_minute_backfill_20260619_r2/ds_minute_sync_20260506_165739.out.json patch | view | raw | blame | history
data/result/stat/ds_minute_backfill_20260619_r2/ds_minute_sync_20260507_170341.err.txt patch | view | raw | blame | history
data/result/stat/ds_minute_backfill_20260619_r2/ds_minute_sync_20260507_170341.out.json patch | view | raw | blame | history
data/result/stat/ds_minute_backfill_20260619_r2/ds_minute_sync_20260508_170943.err.txt patch | view | raw | blame | history
data/result/stat/ds_minute_backfill_20260619_r2/ds_minute_sync_20260508_170943.out.json patch | view | raw | blame | history
data/result/stat/ds_minute_backfill_20260619_r2/ds_minute_sync_20260511_171548.err.txt patch | view | raw | blame | history
data/result/stat/ds_minute_backfill_20260619_r2/ds_minute_sync_20260511_171548.out.json patch | view | raw | blame | history
data/result/stat/ds_minute_backfill_20260619_r2/ds_minute_sync_20260512_172203.err.txt patch | view | raw | blame | history
data/result/stat/ds_minute_backfill_20260619_r2/ds_minute_sync_20260512_172203.out.json patch | view | raw | blame | history
data/result/stat/ds_minute_backfill_20260619_r2/ds_minute_sync_20260513_172805.err.txt patch | view | raw | blame | history
data/result/stat/ds_minute_backfill_20260619_r2/ds_minute_sync_20260513_172805.out.json patch | view | raw | blame | history
data/result/stat/ds_minute_backfill_20260619_r2/ds_minute_sync_20260514_173409.err.txt patch | view | raw | blame | history
data/result/stat/ds_minute_backfill_20260619_r2/ds_minute_sync_20260514_173409.out.json patch | view | raw | blame | history
data/result/stat/ds_minute_backfill_20260619_r2/ds_minute_sync_20260515_174009.err.txt patch | view | raw | blame | history
data/result/stat/ds_minute_backfill_20260619_r2/ds_minute_sync_20260515_174009.out.json patch | view | raw | blame | history
data/result/stat/ds_minute_backfill_20260619_r2/ds_minute_sync_20260518_174617.err.txt patch | view | raw | blame | history
data/result/stat/ds_minute_backfill_20260619_r2/ds_minute_sync_20260518_174617.out.json patch | view | raw | blame | history
data/result/stat/ds_minute_backfill_20260619_r2/ds_minute_sync_20260519_175222.err.txt patch | view | raw | blame | history
data/result/stat/ds_minute_backfill_20260619_r2/ds_minute_sync_20260519_175222.out.json patch | view | raw | blame | history
data/result/stat/ds_minute_backfill_20260619_r2/ds_minute_sync_20260520_175827.err.txt patch | view | raw | blame | history
data/result/stat/ds_minute_backfill_20260619_r2/ds_minute_sync_20260520_175827.out.json patch | view | raw | blame | history
data/result/stat/ds_minute_backfill_20260619_r2/ds_minute_sync_20260521_180436.err.txt patch | view | raw | blame | history
data/result/stat/ds_minute_backfill_20260619_r2/ds_minute_sync_20260521_180436.out.json patch | view | raw | blame | history
data/result/stat/ds_minute_backfill_20260619_r2/ds_minute_sync_20260522_181041.err.txt patch | view | raw | blame | history
data/result/stat/ds_minute_backfill_20260619_r2/ds_minute_sync_20260522_181041.out.json patch | view | raw | blame | history
data/result/stat/ds_minute_backfill_20260619_r2/ds_minute_sync_20260525_181704.err.txt patch | view | raw | blame | history
data/result/stat/ds_minute_backfill_20260619_r2/ds_minute_sync_20260525_181704.out.json patch | view | raw | blame | history
data/result/stat/ds_minute_backfill_20260619_r2/ds_minute_sync_20260526_182307.err.txt patch | view | raw | blame | history
data/result/stat/ds_minute_backfill_20260619_r2/ds_minute_sync_20260526_182307.out.json patch | view | raw | blame | history
data/result/stat/ds_minute_backfill_20260619_r2/ds_minute_sync_20260527_182915.err.txt patch | view | raw | blame | history
data/result/stat/ds_minute_backfill_20260619_r2/ds_minute_sync_20260527_182915.out.json patch | view | raw | blame | history
data/result/stat/ds_minute_backfill_20260619_r2/ds_minute_sync_20260528_183527.err.txt patch | view | raw | blame | history
data/result/stat/ds_minute_backfill_20260619_r2/ds_minute_sync_20260528_183527.out.json patch | view | raw | blame | history
data/result/stat/ds_minute_backfill_20260619_r2/ds_minute_sync_20260529_184149.err.txt patch | view | raw | blame | history
data/result/stat/ds_minute_backfill_20260619_r2/ds_minute_sync_20260529_184149.out.json patch | view | raw | blame | history
data/result/stat/ds_minute_backfill_20260619_r2/ds_minute_sync_20260601_184802.err.txt patch | view | raw | blame | history
data/result/stat/ds_minute_backfill_20260619_r2/ds_minute_sync_20260601_184802.out.json patch | view | raw | blame | history
data/result/stat/ds_minute_backfill_20260619_r2/ds_minute_sync_20260602_185414.err.txt patch | view | raw | blame | history
data/result/stat/ds_minute_backfill_20260619_r2/ds_minute_sync_20260602_185414.out.json patch | view | raw | blame | history
data/result/stat/ds_minute_backfill_20260619_r2/ds_minute_sync_20260603_190024.err.txt patch | view | raw | blame | history
data/result/stat/ds_minute_backfill_20260619_r2/ds_minute_sync_20260603_190024.out.json patch | view | raw | blame | history
data/result/stat/ds_minute_backfill_20260619_r2/ds_minute_sync_20260604_190634.err.txt patch | view | raw | blame | history
data/result/stat/ds_minute_backfill_20260619_r2/ds_minute_sync_20260604_190634.out.json patch | view | raw | blame | history
data/result/stat/ds_minute_backfill_20260619_r2/ds_minute_sync_20260605_191246.err.txt patch | view | raw | blame | history
data/result/stat/ds_minute_backfill_20260619_r2/ds_minute_sync_20260605_191246.out.json patch | view | raw | blame | history
data/result/stat/ds_minute_backfill_20260619_r2/ds_minute_sync_20260608_191917.err.txt patch | view | raw | blame | history
data/result/stat/ds_minute_backfill_20260619_r2/ds_minute_sync_20260608_191917.out.json patch | view | raw | blame | history
data/result/stat/ds_minute_backfill_20260619_r2/ds_minute_sync_20260609_192531.err.txt patch | view | raw | blame | history
data/result/stat/ds_minute_backfill_20260619_r2/ds_minute_sync_20260609_192531.out.json patch | view | raw | blame | history
data/result/stat/ds_minute_backfill_20260619_r2/ds_minute_sync_20260610_193146.err.txt patch | view | raw | blame | history
data/result/stat/ds_minute_backfill_20260619_r2/ds_minute_sync_20260610_193146.out.json patch | view | raw | blame | history
data/result/stat/ds_minute_backfill_20260619_r2/ds_minute_sync_20260611_193757.err.txt patch | view | raw | blame | history
data/result/stat/ds_minute_backfill_20260619_r2/ds_minute_sync_20260611_193757.out.json patch | view | raw | blame | history
data/result/stat/ds_minute_backfill_20260619_r2/ds_minute_sync_20260612_194411.err.txt patch | view | raw | blame | history
data/result/stat/ds_minute_backfill_20260619_r2/ds_minute_sync_20260612_194411.out.json patch | view | raw | blame | history
data/result/stat/ds_minute_backfill_20260619_r2/ds_minute_sync_20260615_195031.err.txt patch | view | raw | blame | history
data/result/stat/ds_minute_backfill_20260619_r2/ds_minute_sync_20260615_195031.out.json patch | view | raw | blame | history
data/result/stat/ds_minute_backfill_20260619_r2/ds_minute_sync_20260616_195644.err.txt patch | view | raw | blame | history
data/result/stat/ds_minute_backfill_20260619_r2/ds_minute_sync_20260616_195644.out.json patch | view | raw | blame | history
data/result/stat/ds_minute_backfill_20260619_r2/ds_minute_sync_20260617_200258.err.txt patch | view | raw | blame | history
data/result/stat/ds_minute_backfill_20260619_r2/ds_minute_sync_20260617_200258.out.json patch | view | raw | blame | history
data/result/stat/ds_minute_backfill_20260619_r2/summary.tsv 38 ●●●●● patch | view | raw | blame | history
data/全复权分钟线导入说明.md 151 ●●●●● patch | view | raw | blame | history
data/目录导读.md 11 ●●●●● patch | view | raw | blame | history
scripts/ds_minute_backfill.ps1 61 ●●●●● patch | view | raw | blame | history
scripts/import_full_adj_minute_csv.py 330 ●●●●● patch | view | raw | blame | history
scripts/kline_front_incremental_sync.py 3 ●●●● patch | view | raw | blame | history
全局存储体系.md 4 ●●●● patch | view | raw | blame | history
全局数据格式.md 61 ●●●●● patch | view | raw | blame | history
管理执行日志.md 140 ●●●●● patch | view | raw | blame | history
.gitignore
@@ -7,6 +7,7 @@
scripts/**/__pycache__/
scripts/**/*.pyc
data/*.local.md
data/raw/
管理端上下文.md
MB-X错误日志.md
MB-X错误日志.md
data/result/stat/ds_minute_backfill_20260619/background.stderr.log
New file
@@ -0,0 +1,7 @@
Select-String : Â·¾¶ÖоßÓзǷ¨×Ö·û¡£
ËùÔÚλÖàD:\manage_system\scripts\ds_minute_backfill.ps1:15 ×Ö·û: 32
+ ... PASSWORD = (Select-String -LiteralPath $localDoc -Pattern '密码:`([^`] ...
+                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [Select-String], ArgumentException
    + FullyQualifiedErrorId : System.ArgumentException,Microsoft.PowerShell.Commands.SelectStringCommand
data/result/stat/ds_minute_backfill_20260619/background.stdout.log
data/result/stat/ds_minute_backfill_20260619_r2/background.stderr.log
data/result/stat/ds_minute_backfill_20260619_r2/background.stdout.log
data/result/stat/ds_minute_backfill_20260619_r2/dates.txt
New file
@@ -0,0 +1,37 @@
2026-04-23
2026-04-24
2026-04-27
2026-04-28
2026-04-29
2026-04-30
2026-05-06
2026-05-07
2026-05-08
2026-05-11
2026-05-12
2026-05-13
2026-05-14
2026-05-15
2026-05-18
2026-05-19
2026-05-20
2026-05-21
2026-05-22
2026-05-25
2026-05-26
2026-05-27
2026-05-28
2026-05-29
2026-06-01
2026-06-02
2026-06-03
2026-06-04
2026-06-05
2026-06-08
2026-06-09
2026-06-10
2026-06-11
2026-06-12
2026-06-15
2026-06-16
2026-06-17
data/result/stat/ds_minute_backfill_20260619_r2/ds_minute_sync_20260423_162049.err.txt
data/result/stat/ds_minute_backfill_20260619_r2/ds_minute_sync_20260423_162049.out.json
Binary files differ
data/result/stat/ds_minute_backfill_20260619_r2/ds_minute_sync_20260424_162709.err.txt
data/result/stat/ds_minute_backfill_20260619_r2/ds_minute_sync_20260424_162709.out.json
Binary files differ
data/result/stat/ds_minute_backfill_20260619_r2/ds_minute_sync_20260427_163323.err.txt
data/result/stat/ds_minute_backfill_20260619_r2/ds_minute_sync_20260427_163323.out.json
Binary files differ
data/result/stat/ds_minute_backfill_20260619_r2/ds_minute_sync_20260428_163932.err.txt
data/result/stat/ds_minute_backfill_20260619_r2/ds_minute_sync_20260428_163932.out.json
Binary files differ
data/result/stat/ds_minute_backfill_20260619_r2/ds_minute_sync_20260429_164538.err.txt
data/result/stat/ds_minute_backfill_20260619_r2/ds_minute_sync_20260429_164538.out.json
Binary files differ
data/result/stat/ds_minute_backfill_20260619_r2/ds_minute_sync_20260430_165136.err.txt
data/result/stat/ds_minute_backfill_20260619_r2/ds_minute_sync_20260430_165136.out.json
Binary files differ
data/result/stat/ds_minute_backfill_20260619_r2/ds_minute_sync_20260506_165739.err.txt
data/result/stat/ds_minute_backfill_20260619_r2/ds_minute_sync_20260506_165739.out.json
Binary files differ
data/result/stat/ds_minute_backfill_20260619_r2/ds_minute_sync_20260507_170341.err.txt
data/result/stat/ds_minute_backfill_20260619_r2/ds_minute_sync_20260507_170341.out.json
Binary files differ
data/result/stat/ds_minute_backfill_20260619_r2/ds_minute_sync_20260508_170943.err.txt
data/result/stat/ds_minute_backfill_20260619_r2/ds_minute_sync_20260508_170943.out.json
Binary files differ
data/result/stat/ds_minute_backfill_20260619_r2/ds_minute_sync_20260511_171548.err.txt
data/result/stat/ds_minute_backfill_20260619_r2/ds_minute_sync_20260511_171548.out.json
Binary files differ
data/result/stat/ds_minute_backfill_20260619_r2/ds_minute_sync_20260512_172203.err.txt
data/result/stat/ds_minute_backfill_20260619_r2/ds_minute_sync_20260512_172203.out.json
Binary files differ
data/result/stat/ds_minute_backfill_20260619_r2/ds_minute_sync_20260513_172805.err.txt
data/result/stat/ds_minute_backfill_20260619_r2/ds_minute_sync_20260513_172805.out.json
Binary files differ
data/result/stat/ds_minute_backfill_20260619_r2/ds_minute_sync_20260514_173409.err.txt
data/result/stat/ds_minute_backfill_20260619_r2/ds_minute_sync_20260514_173409.out.json
Binary files differ
data/result/stat/ds_minute_backfill_20260619_r2/ds_minute_sync_20260515_174009.err.txt
data/result/stat/ds_minute_backfill_20260619_r2/ds_minute_sync_20260515_174009.out.json
Binary files differ
data/result/stat/ds_minute_backfill_20260619_r2/ds_minute_sync_20260518_174617.err.txt
data/result/stat/ds_minute_backfill_20260619_r2/ds_minute_sync_20260518_174617.out.json
Binary files differ
data/result/stat/ds_minute_backfill_20260619_r2/ds_minute_sync_20260519_175222.err.txt
data/result/stat/ds_minute_backfill_20260619_r2/ds_minute_sync_20260519_175222.out.json
Binary files differ
data/result/stat/ds_minute_backfill_20260619_r2/ds_minute_sync_20260520_175827.err.txt
data/result/stat/ds_minute_backfill_20260619_r2/ds_minute_sync_20260520_175827.out.json
Binary files differ
data/result/stat/ds_minute_backfill_20260619_r2/ds_minute_sync_20260521_180436.err.txt
data/result/stat/ds_minute_backfill_20260619_r2/ds_minute_sync_20260521_180436.out.json
Binary files differ
data/result/stat/ds_minute_backfill_20260619_r2/ds_minute_sync_20260522_181041.err.txt
data/result/stat/ds_minute_backfill_20260619_r2/ds_minute_sync_20260522_181041.out.json
Binary files differ
data/result/stat/ds_minute_backfill_20260619_r2/ds_minute_sync_20260525_181704.err.txt
data/result/stat/ds_minute_backfill_20260619_r2/ds_minute_sync_20260525_181704.out.json
Binary files differ
data/result/stat/ds_minute_backfill_20260619_r2/ds_minute_sync_20260526_182307.err.txt
data/result/stat/ds_minute_backfill_20260619_r2/ds_minute_sync_20260526_182307.out.json
Binary files differ
data/result/stat/ds_minute_backfill_20260619_r2/ds_minute_sync_20260527_182915.err.txt
data/result/stat/ds_minute_backfill_20260619_r2/ds_minute_sync_20260527_182915.out.json
Binary files differ
data/result/stat/ds_minute_backfill_20260619_r2/ds_minute_sync_20260528_183527.err.txt
data/result/stat/ds_minute_backfill_20260619_r2/ds_minute_sync_20260528_183527.out.json
Binary files differ
data/result/stat/ds_minute_backfill_20260619_r2/ds_minute_sync_20260529_184149.err.txt
data/result/stat/ds_minute_backfill_20260619_r2/ds_minute_sync_20260529_184149.out.json
Binary files differ
data/result/stat/ds_minute_backfill_20260619_r2/ds_minute_sync_20260601_184802.err.txt
data/result/stat/ds_minute_backfill_20260619_r2/ds_minute_sync_20260601_184802.out.json
Binary files differ
data/result/stat/ds_minute_backfill_20260619_r2/ds_minute_sync_20260602_185414.err.txt
data/result/stat/ds_minute_backfill_20260619_r2/ds_minute_sync_20260602_185414.out.json
Binary files differ
data/result/stat/ds_minute_backfill_20260619_r2/ds_minute_sync_20260603_190024.err.txt
data/result/stat/ds_minute_backfill_20260619_r2/ds_minute_sync_20260603_190024.out.json
Binary files differ
data/result/stat/ds_minute_backfill_20260619_r2/ds_minute_sync_20260604_190634.err.txt
data/result/stat/ds_minute_backfill_20260619_r2/ds_minute_sync_20260604_190634.out.json
Binary files differ
data/result/stat/ds_minute_backfill_20260619_r2/ds_minute_sync_20260605_191246.err.txt
data/result/stat/ds_minute_backfill_20260619_r2/ds_minute_sync_20260605_191246.out.json
Binary files differ
data/result/stat/ds_minute_backfill_20260619_r2/ds_minute_sync_20260608_191917.err.txt
data/result/stat/ds_minute_backfill_20260619_r2/ds_minute_sync_20260608_191917.out.json
Binary files differ
data/result/stat/ds_minute_backfill_20260619_r2/ds_minute_sync_20260609_192531.err.txt
data/result/stat/ds_minute_backfill_20260619_r2/ds_minute_sync_20260609_192531.out.json
Binary files differ
data/result/stat/ds_minute_backfill_20260619_r2/ds_minute_sync_20260610_193146.err.txt
data/result/stat/ds_minute_backfill_20260619_r2/ds_minute_sync_20260610_193146.out.json
Binary files differ
data/result/stat/ds_minute_backfill_20260619_r2/ds_minute_sync_20260611_193757.err.txt
data/result/stat/ds_minute_backfill_20260619_r2/ds_minute_sync_20260611_193757.out.json
Binary files differ
data/result/stat/ds_minute_backfill_20260619_r2/ds_minute_sync_20260612_194411.err.txt
data/result/stat/ds_minute_backfill_20260619_r2/ds_minute_sync_20260612_194411.out.json
Binary files differ
data/result/stat/ds_minute_backfill_20260619_r2/ds_minute_sync_20260615_195031.err.txt
data/result/stat/ds_minute_backfill_20260619_r2/ds_minute_sync_20260615_195031.out.json
Binary files differ
data/result/stat/ds_minute_backfill_20260619_r2/ds_minute_sync_20260616_195644.err.txt
data/result/stat/ds_minute_backfill_20260619_r2/ds_minute_sync_20260616_195644.out.json
Binary files differ
data/result/stat/ds_minute_backfill_20260619_r2/ds_minute_sync_20260617_200258.err.txt
data/result/stat/ds_minute_backfill_20260619_r2/ds_minute_sync_20260617_200258.out.json
Binary files differ
data/result/stat/ds_minute_backfill_20260619_r2/summary.tsv
New file
@@ -0,0 +1,38 @@
date    status    run_id    started_at    finished_at
2026-04-23    SUCCESS    ds_minute_sync_20260423_162049    2026-06-19T16:20:49    2026-06-19T16:27:09
2026-04-24    SUCCESS    ds_minute_sync_20260424_162709    2026-06-19T16:27:09    2026-06-19T16:33:23
2026-04-27    SUCCESS    ds_minute_sync_20260427_163323    2026-06-19T16:33:23    2026-06-19T16:39:32
2026-04-28    SUCCESS    ds_minute_sync_20260428_163932    2026-06-19T16:39:32    2026-06-19T16:45:38
2026-04-29    SUCCESS    ds_minute_sync_20260429_164538    2026-06-19T16:45:38    2026-06-19T16:51:36
2026-04-30    SUCCESS    ds_minute_sync_20260430_165136    2026-06-19T16:51:36    2026-06-19T16:57:39
2026-05-06    SUCCESS    ds_minute_sync_20260506_165739    2026-06-19T16:57:39    2026-06-19T17:03:41
2026-05-07    SUCCESS    ds_minute_sync_20260507_170341    2026-06-19T17:03:41    2026-06-19T17:09:43
2026-05-08    SUCCESS    ds_minute_sync_20260508_170943    2026-06-19T17:09:43    2026-06-19T17:15:48
2026-05-11    SUCCESS    ds_minute_sync_20260511_171548    2026-06-19T17:15:48    2026-06-19T17:22:03
2026-05-12    SUCCESS    ds_minute_sync_20260512_172203    2026-06-19T17:22:03    2026-06-19T17:28:05
2026-05-13    SUCCESS    ds_minute_sync_20260513_172805    2026-06-19T17:28:05    2026-06-19T17:34:09
2026-05-14    SUCCESS    ds_minute_sync_20260514_173409    2026-06-19T17:34:09    2026-06-19T17:40:09
2026-05-15    SUCCESS    ds_minute_sync_20260515_174009    2026-06-19T17:40:09    2026-06-19T17:46:17
2026-05-18    SUCCESS    ds_minute_sync_20260518_174617    2026-06-19T17:46:17    2026-06-19T17:52:22
2026-05-19    SUCCESS    ds_minute_sync_20260519_175222    2026-06-19T17:52:22    2026-06-19T17:58:27
2026-05-20    SUCCESS    ds_minute_sync_20260520_175827    2026-06-19T17:58:27    2026-06-19T18:04:36
2026-05-21    SUCCESS    ds_minute_sync_20260521_180436    2026-06-19T18:04:36    2026-06-19T18:10:41
2026-05-22    SUCCESS    ds_minute_sync_20260522_181041    2026-06-19T18:10:41    2026-06-19T18:17:04
2026-05-25    SUCCESS    ds_minute_sync_20260525_181704    2026-06-19T18:17:04    2026-06-19T18:23:07
2026-05-26    SUCCESS    ds_minute_sync_20260526_182307    2026-06-19T18:23:07    2026-06-19T18:29:15
2026-05-27    SUCCESS    ds_minute_sync_20260527_182915    2026-06-19T18:29:15    2026-06-19T18:35:27
2026-05-28    SUCCESS    ds_minute_sync_20260528_183527    2026-06-19T18:35:27    2026-06-19T18:41:49
2026-05-29    SUCCESS    ds_minute_sync_20260529_184149    2026-06-19T18:41:49    2026-06-19T18:48:02
2026-06-01    SUCCESS    ds_minute_sync_20260601_184802    2026-06-19T18:48:02    2026-06-19T18:54:14
2026-06-02    SUCCESS    ds_minute_sync_20260602_185414    2026-06-19T18:54:14    2026-06-19T19:00:24
2026-06-03    SUCCESS    ds_minute_sync_20260603_190024    2026-06-19T19:00:24    2026-06-19T19:06:34
2026-06-04    SUCCESS    ds_minute_sync_20260604_190634    2026-06-19T19:06:34    2026-06-19T19:12:46
2026-06-05    SUCCESS    ds_minute_sync_20260605_191246    2026-06-19T19:12:46    2026-06-19T19:19:17
2026-06-08    SUCCESS    ds_minute_sync_20260608_191917    2026-06-19T19:19:17    2026-06-19T19:25:31
2026-06-09    SUCCESS    ds_minute_sync_20260609_192531    2026-06-19T19:25:31    2026-06-19T19:31:46
2026-06-10    SUCCESS    ds_minute_sync_20260610_193146    2026-06-19T19:31:46    2026-06-19T19:37:57
2026-06-11    SUCCESS    ds_minute_sync_20260611_193757    2026-06-19T19:37:57    2026-06-19T19:44:11
2026-06-12    SUCCESS    ds_minute_sync_20260612_194411    2026-06-19T19:44:11    2026-06-19T19:50:31
2026-06-15    SUCCESS    ds_minute_sync_20260615_195031    2026-06-19T19:50:31    2026-06-19T19:56:44
2026-06-16    SUCCESS    ds_minute_sync_20260616_195644    2026-06-19T19:56:44    2026-06-19T20:02:58
2026-06-17    SUCCESS    ds_minute_sync_20260617_200258    2026-06-19T20:02:58    2026-06-19T20:09:14
data/全复权分钟线导入说明.md
New file
@@ -0,0 +1,151 @@
# 全复权分钟线导入说明
创建时间:2026-06-14
## 1. 数据定位
本次新增的是 A 股全复权 1 分钟 K 线数据,作为全局 MySQL 行情底座中的独立公共表使用。
目标表:
- `a_share_minute_price_full_adj`
- `a_share_minute_full_adj_import_run`
- `a_share_minute_full_adj_import_file_log`
使用边界:
- 这是全复权分钟线,不替代当前默认分钟线 `a_share_minute_price`。
- 这是独立口径,不与前复权同步影子表 `a_share_minute_price_front_sync` 混用。
- 查询必须带 `trade_date`、`symbol`,最好再带 `trade_time` 范围;禁止无边界全表扫描。
## 2. 来源
源压缩包:
```text
D:\A股日级行情数据近两年2023csv.rar
```
解压目录:
```text
D:\manage_system\data\raw\a_share_minute_full_adj_2023_2026_csv
```
压缩包目录结构:
```text
2023_front_m/<市场>/price_<股票代码>.csv
```
CSV 字段:
```text
timetag,open,high,low,close,volumn,amount
```
字段说明:
- `timetag`:分钟 bar 时间,格式如 `20230523 09:30:00`
- `open/high/low/close`:全复权 OHLC
- `volumn`:源文件字段名如此拼写,入库后映射为 `volume`
- `amount`:成交额
## 3. 导入结果
导入 run_id:
```text
full_adj_minute_20260614_rar
```
导入结果:
| 项目 | 数值 |
|---|---:|
| 源 CSV 文件数 | 3161 |
| 已处理文件数 | 3161 |
| 有效入库行数 | 422,373,172 |
| 非空数据起始日期 | 2023-03-24 |
| 非空数据结束日期 | 2026-06-12 |
| 源 0 字节文件数 | 732 |
按市场统计:
| 市场 | 文件数 | 入库行数 | 0 字节文件数 |
|---|---:|---:|---:|
| BJ | 320 | 44,413,040 | 0 |
| SH | 2314 | 331,542,089 | 508 |
| SZ | 527 | 46,418,043 | 224 |
0 字节源文件已记录到 `a_share_minute_full_adj_import_file_log`,不写入行情表。
## 4. 表结构摘要
`a_share_minute_price_full_adj` 主键:
```text
symbol + trade_date + trade_time
```
核心字段:
| 字段 | 含义 |
|---|---|
| `trade_date` | 交易日 |
| `trade_time` | 分钟时间 |
| `bar_time` | 完整 datetime |
| `symbol` | 股票代码,格式如 `600000.SH` |
| `market` | `SH` / `SZ` / `BJ` |
| `open_price` | 全复权开盘价 |
| `high_price` | 全复权最高价 |
| `low_price` | 全复权最低价 |
| `close_price` | 全复权收盘价 |
| `volume` | 源成交量 |
| `amount` | 源成交额 |
| `source_file` | 解压后相对文件路径 |
| `source_archive` | 来源压缩包路径 |
| `import_run_id` | 导入批次 |
## 5. 导入脚本与证据
导入脚本:
```text
scripts/import_full_adj_minute_csv.py
```
运行 wrapper:
```text
tmp/run_full_adj_minute_import_20260614.ps1
```
证据日志:
```text
tmp/full_adj_minute_import_20260614.stdout.log
tmp/full_adj_minute_import_20260614.stderr.log
tmp/full_adj_minute_import_20260614.wrapper.log
tmp/rar_list_A股日级行情数据近两年2023csv_20260614.txt
tmp/unrar_A股日级行情数据近两年2023csv_20260614.log
```
## 6. 查询示例
```sql
SELECT *
FROM a_share_minute_price_full_adj
WHERE symbol = '600000.SH'
  AND trade_date = '2024-01-02'
  AND trade_time BETWEEN '09:30:00' AND '10:00:00'
ORDER BY trade_time;
```
禁止示例:
```sql
SELECT COUNT(*) FROM a_share_minute_price_full_adj;
```
全表统计必须优先使用导入运行表和文件日志表。
data/目录导读.md
@@ -14,10 +14,19 @@
## 2. 当前状态
当前目录暂不放置具体数据文件,仅保留本导读文件用于占位和 Git 跟踪。
当前目录保存全局数据源说明、数据库索引说明、导入脚本说明和可跨项目复用的数据入口说明。
后续新增全局数据材料时,应先确认其是否满足跨项目复用、统一口径和长期维护要求。
当前已登记材料:
| 文件 | 用途 |
|---|---|
| `数据库索引数据.local.md` | 本机 MySQL 连接和历史索引说明;包含本机敏感信息,不提交远程 |
| `HTTP与MySQL使用说明.md` | 外部前复权 K 线服务 HTTP/MySQL 使用说明 |
| `K线同步到本地数据库全景说明.md` | 前复权 K 线同步到本地数据库的全景说明 |
| `全复权分钟线导入说明.md` | 2026-06-14 新增全复权 1 分钟 K 线入库说明 |
## 3. 使用原则
1. 不存放临时文件、缓存文件或单项目私有数据。
scripts/ds_minute_backfill.ps1
New file
@@ -0,0 +1,61 @@
param(
  [string]$StartDate = "2026-04-23",
  [string]$EndDate = "2026-06-17",
  [string]$LogDir = "D:\manage_system\data\result\stat\ds_minute_backfill_20260619"
)
$ErrorActionPreference = "Stop"
$root = Split-Path -Parent $PSScriptRoot
$script = Join-Path $root "scripts\kline_front_incremental_sync.py"
$localDoc = Get-ChildItem -LiteralPath (Join-Path $root "data") -Filter "*.local.md" |
  Select-String -Pattern "mysql://root:" -List |
  Select-Object -First 1 -ExpandProperty Path
$sourceDoc = Get-ChildItem -LiteralPath (Join-Path $root "data") -Filter "*.local.md" |
  Select-String -Pattern "trading_xuntou" -List |
  Select-Object -First 1 -ExpandProperty Path
New-Item -ItemType Directory -Force -Path $LogDir | Out-Null
$env:TIANXIA_MYSQL_PASSWORD = (Select-String -LiteralPath $localDoc -Pattern 'mysql://root:([^@]+)@' | Select-Object -First 1).Matches[0].Groups[1].Value
$env:KLINE_SOURCE_MYSQL_PASSWORD = (Select-String -LiteralPath $sourceDoc -Pattern 'Password.*`([^`]+)`' | Select-Object -First 1).Matches[0].Groups[1].Value
$datesPath = Join-Path $LogDir "dates.txt"
@"
import os, pymysql
source = pymysql.connect(host='317w7246e5.vicp.fun', port=50176, user='root', password=os.environ['KLINE_SOURCE_MYSQL_PASSWORD'], database='trading_xuntou', charset='utf8mb4', connect_timeout=10, read_timeout=120)
local = pymysql.connect(host='127.0.0.1', port=3306, user='root', password=os.environ['TIANXIA_MYSQL_PASSWORD'], database='tianxia', charset='utf8mb4', connect_timeout=10, read_timeout=120)
with source.cursor() as cur:
    cur.execute("SELECT trade_date FROM cn_stock_kline_front_coverage_daily WHERE period='1m' AND trade_date BETWEEN %s AND %s AND row_count > 0 ORDER BY trade_date", ('$StartDate', '$EndDate'))
    source_dates = [str(row[0]) for row in cur.fetchall()]
with local.cursor() as cur:
    cur.execute("SELECT DISTINCT trade_date FROM a_share_minute_price WHERE trade_date BETWEEN %s AND %s", ('$StartDate', '$EndDate'))
    done_dates = {str(row[0]) for row in cur.fetchall()}
for d in source_dates:
    if d not in done_dates:
        print(d)
source.close()
local.close()
"@ | python - | Set-Content -LiteralPath $datesPath -Encoding ASCII
$dates = Get-Content -LiteralPath $datesPath | Where-Object { $_ -match '^\d{4}-\d{2}-\d{2}$' }
$summaryPath = Join-Path $LogDir "summary.tsv"
"date`tstatus`trun_id`tstarted_at`tfinished_at" | Set-Content -LiteralPath $summaryPath -Encoding UTF8
foreach ($date in $dates) {
  $runId = "ds_minute_sync_" + ($date -replace "-", "") + "_" + (Get-Date -Format "HHmmss")
  $started = Get-Date -Format "s"
  $out = Join-Path $LogDir "$runId.out.json"
  $err = Join-Path $LogDir "$runId.err.txt"
  try {
    python $script --run-id $runId --periods 1m --start-date $date --end-date $date --minute-max-minutes-per-batch 120 --minute-symbols-per-batch 200 --append-to-main > $out 2> $err
    $status = if ($LASTEXITCODE -eq 0) { "SUCCESS" } else { "FAILED_$LASTEXITCODE" }
  } catch {
    $_ | Out-File -LiteralPath $err -Append -Encoding UTF8
    $status = "FAILED_EXCEPTION"
  }
  $finished = Get-Date -Format "s"
  "$date`t$status`t$runId`t$started`t$finished" | Add-Content -LiteralPath $summaryPath -Encoding UTF8
  if ($status -notlike "SUCCESS") {
    break
  }
}
scripts/import_full_adj_minute_csv.py
New file
@@ -0,0 +1,330 @@
from __future__ import annotations
import argparse
import os
import re
import sys
import time
from datetime import datetime
from pathlib import Path
import pymysql
MARKET_SUFFIX = {
    "SH": ".SH",
    "SZ": ".SZ",
    "BJ": ".BJ",
}
def connect(args: argparse.Namespace):
    password = args.password or os.environ.get("TIANXIA_MYSQL_PASSWORD")
    if not password:
        raise RuntimeError("missing MySQL password: pass --password or set TIANXIA_MYSQL_PASSWORD")
    return pymysql.connect(
        host=args.host,
        port=args.port,
        user=args.user,
        password=password,
        database=args.database,
        charset="utf8mb4",
        autocommit=False,
        local_infile=True,
    )
def ensure_schema(conn) -> None:
    ddl = [
        """
        CREATE TABLE IF NOT EXISTS a_share_minute_price_full_adj (
          trade_date date NOT NULL,
          trade_time time NOT NULL,
          bar_time datetime NOT NULL,
          symbol char(9) NOT NULL,
          market varchar(8) NOT NULL,
          open_price decimal(14,4) NULL,
          high_price decimal(14,4) NULL,
          low_price decimal(14,4) NULL,
          close_price decimal(14,4) NULL,
          volume decimal(24,4) NULL,
          amount decimal(24,4) NULL,
          source_file varchar(255) NOT NULL,
          source_archive varchar(255) NOT NULL,
          import_run_id varchar(96) NOT NULL,
          imported_at timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
          PRIMARY KEY (symbol, trade_date, trade_time),
          KEY idx_full_adj_minute_date_symbol_time (trade_date, symbol, trade_time),
          KEY idx_full_adj_minute_run (import_run_id)
        ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
        """,
        """
        CREATE TABLE IF NOT EXISTS a_share_minute_full_adj_import_run (
          run_id varchar(96) NOT NULL,
          started_at datetime NOT NULL,
          finished_at datetime NULL,
          status varchar(32) NOT NULL,
          source_archive varchar(512) NOT NULL,
          source_root varchar(512) NOT NULL,
          files_total int NOT NULL DEFAULT 0,
          files_loaded int NOT NULL DEFAULT 0,
          rows_loaded bigint NOT NULL DEFAULT 0,
          min_trade_date date NULL,
          max_trade_date date NULL,
          error_message text NULL,
          PRIMARY KEY (run_id)
        ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
        """,
        """
        CREATE TABLE IF NOT EXISTS a_share_minute_full_adj_import_file_log (
          id bigint NOT NULL AUTO_INCREMENT,
          run_id varchar(96) NOT NULL,
          symbol char(9) NOT NULL,
          market varchar(8) NOT NULL,
          source_file varchar(512) NOT NULL,
          file_size bigint NOT NULL,
          rows_loaded bigint NOT NULL,
          started_at datetime NOT NULL,
          finished_at datetime NOT NULL,
          duration_ms bigint NOT NULL,
          status varchar(32) NOT NULL,
          error_message text NULL,
          PRIMARY KEY (id),
          UNIQUE KEY uq_full_adj_file_run (run_id, source_file),
          KEY idx_full_adj_file_symbol (symbol),
          KEY idx_full_adj_file_status (status)
        ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
        """,
    ]
    with conn.cursor() as cur:
        for sql in ddl:
            cur.execute(sql)
    conn.commit()
def discover_files(root: Path) -> list[Path]:
    files = sorted(root.rglob("price_*.csv"))
    if not files:
        raise RuntimeError(f"no price_*.csv files found under {root}")
    return files
def symbol_for(path: Path) -> tuple[str, str]:
    market = path.parent.name.upper()
    suffix = MARKET_SUFFIX.get(market)
    if not suffix:
        raise RuntimeError(f"unsupported market directory {market}: {path}")
    m = re.match(r"price_(\d{6})\.csv$", path.name, re.IGNORECASE)
    if not m:
        raise RuntimeError(f"unsupported file name: {path}")
    return m.group(1) + suffix, market
def init_run(conn, run_id: str, source_archive: str, source_root: str, files_total: int) -> None:
    with conn.cursor() as cur:
        cur.execute(
            """
            INSERT INTO a_share_minute_full_adj_import_run
              (run_id, started_at, status, source_archive, source_root, files_total)
            VALUES (%s, NOW(), 'running', %s, %s, %s)
            ON DUPLICATE KEY UPDATE
              status='running',
              source_archive=VALUES(source_archive),
              source_root=VALUES(source_root),
              files_total=VALUES(files_total),
              error_message=NULL
            """,
            (run_id, source_archive, source_root, files_total),
        )
    conn.commit()
def finish_run(conn, run_id: str, status: str, error: str | None = None) -> None:
    with conn.cursor() as cur:
        cur.execute(
            """
            UPDATE a_share_minute_full_adj_import_run r
            LEFT JOIN (
              SELECT
                import_run_id,
                COUNT(*) AS rows_loaded,
                MIN(trade_date) AS min_trade_date,
                MAX(trade_date) AS max_trade_date
              FROM a_share_minute_price_full_adj
              WHERE import_run_id=%s
              GROUP BY import_run_id
            ) x ON x.import_run_id = r.run_id
            SET
              r.finished_at=NOW(),
              r.status=%s,
              r.rows_loaded=COALESCE(x.rows_loaded, r.rows_loaded),
              r.min_trade_date=COALESCE(x.min_trade_date, r.min_trade_date),
              r.max_trade_date=COALESCE(x.max_trade_date, r.max_trade_date),
              r.error_message=%s
            WHERE r.run_id=%s
            """,
            (run_id, status, error, run_id),
        )
    conn.commit()
def load_file(conn, path: Path, root: Path, archive: str, run_id: str) -> int:
    symbol, market = symbol_for(path)
    rel = str(path.relative_to(root)).replace("\\", "/")
    started = datetime.now()
    t0 = time.perf_counter()
    with conn.cursor() as cur:
        cur.execute("DROP TEMPORARY TABLE IF EXISTS tmp_full_adj_minute_csv")
        cur.execute(
            """
            CREATE TEMPORARY TABLE tmp_full_adj_minute_csv (
              timetag varchar(19) NOT NULL,
              open_price decimal(14,4) NULL,
              high_price decimal(14,4) NULL,
              low_price decimal(14,4) NULL,
              close_price decimal(14,4) NULL,
              volume decimal(24,4) NULL,
              amount decimal(24,4) NULL
            ) ENGINE=InnoDB
            """
        )
        cur.execute(
            """
            LOAD DATA LOCAL INFILE %s
            INTO TABLE tmp_full_adj_minute_csv
            CHARACTER SET utf8mb4
            FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '"'
            LINES TERMINATED BY '\n'
            IGNORE 1 LINES
            (timetag, open_price, high_price, low_price, close_price, volume, amount)
            """,
            (str(path),),
        )
        loaded_tmp = cur.rowcount
        cur.execute(
            """
            INSERT INTO a_share_minute_price_full_adj
              (trade_date, trade_time, bar_time, symbol, market,
               open_price, high_price, low_price, close_price, volume, amount,
               source_file, source_archive, import_run_id)
            SELECT
              DATE(STR_TO_DATE(timetag, '%%Y%%m%%d %%H:%%i:%%s')),
              TIME(STR_TO_DATE(timetag, '%%Y%%m%%d %%H:%%i:%%s')),
              STR_TO_DATE(timetag, '%%Y%%m%%d %%H:%%i:%%s'),
              %s,
              %s,
              open_price,
              high_price,
              low_price,
              close_price,
              volume,
              amount,
              %s,
              %s,
              %s
            FROM tmp_full_adj_minute_csv
            ON DUPLICATE KEY UPDATE
              open_price=VALUES(open_price),
              high_price=VALUES(high_price),
              low_price=VALUES(low_price),
              close_price=VALUES(close_price),
              volume=VALUES(volume),
              amount=VALUES(amount),
              source_file=VALUES(source_file),
              source_archive=VALUES(source_archive),
              import_run_id=VALUES(import_run_id),
              imported_at=CURRENT_TIMESTAMP
            """,
            (symbol, market, rel, archive, run_id),
        )
        inserted = cur.rowcount
        duration_ms = int((time.perf_counter() - t0) * 1000)
        cur.execute(
            """
            INSERT INTO a_share_minute_full_adj_import_file_log
              (run_id, symbol, market, source_file, file_size, rows_loaded,
               started_at, finished_at, duration_ms, status)
            VALUES (%s, %s, %s, %s, %s, %s, %s, NOW(), %s, 'loaded')
            ON DUPLICATE KEY UPDATE
              rows_loaded=VALUES(rows_loaded),
              file_size=VALUES(file_size),
              finished_at=VALUES(finished_at),
              duration_ms=VALUES(duration_ms),
              status='loaded',
              error_message=NULL
            """,
            (run_id, symbol, market, rel, path.stat().st_size, loaded_tmp, started, duration_ms),
        )
        cur.execute(
            """
            UPDATE a_share_minute_full_adj_import_run
            SET files_loaded = (
              SELECT COUNT(*) FROM a_share_minute_full_adj_import_file_log
              WHERE run_id=%s AND status='loaded'
            )
            WHERE run_id=%s
            """,
            (run_id, run_id),
        )
    conn.commit()
    return loaded_tmp if loaded_tmp >= 0 else inserted
def main() -> int:
    parser = argparse.ArgumentParser()
    parser.add_argument("--source-root", required=True)
    parser.add_argument("--source-archive", required=True)
    parser.add_argument("--run-id")
    parser.add_argument("--host", default="127.0.0.1")
    parser.add_argument("--port", type=int, default=3306)
    parser.add_argument("--user", default="root")
    parser.add_argument("--password")
    parser.add_argument("--database", default="tianxia")
    parser.add_argument("--limit", type=int)
    parser.add_argument("--skip-loaded", action="store_true")
    args = parser.parse_args()
    root = Path(args.source_root).resolve()
    files = discover_files(root)
    if args.limit:
        files = files[: args.limit]
    run_id = args.run_id or "full_adj_minute_" + datetime.now().strftime("%Y%m%d_%H%M%S")
    conn = connect(args)
    try:
        ensure_schema(conn)
        init_run(conn, run_id, args.source_archive, str(root), len(files))
        loaded_total = 0
        with conn.cursor() as cur:
            loaded_files = set()
            if args.skip_loaded:
                cur.execute(
                    "SELECT source_file FROM a_share_minute_full_adj_import_file_log WHERE run_id=%s AND status='loaded'",
                    (run_id,),
                )
                loaded_files = {row[0] for row in cur.fetchall()}
        for idx, path in enumerate(files, 1):
            rel = str(path.relative_to(root)).replace("\\", "/")
            if rel in loaded_files:
                continue
            rows = load_file(conn, path, root, args.source_archive, run_id)
            loaded_total += rows
            if idx % 10 == 0 or idx == 1 or idx == len(files):
                print(f"{datetime.now():%Y-%m-%d %H:%M:%S} loaded {idx}/{len(files)} files; last={rel}; rows={rows}; total_rows_seen={loaded_total}", flush=True)
        finish_run(conn, run_id, "completed")
        print(f"completed run_id={run_id} files={len(files)} rows_seen={loaded_total}")
        return 0
    except Exception as exc:
        conn.rollback()
        try:
            finish_run(conn, run_id, "failed", str(exc))
        except Exception:
            pass
        print(f"failed run_id={run_id}: {exc}", file=sys.stderr)
        return 1
    finally:
        conn.close()
if __name__ == "__main__":
    raise SystemExit(main())
scripts/kline_front_incremental_sync.py
@@ -99,9 +99,10 @@
        extra.extend(["--batch", "--raw"])
    if skip_column_names:
        extra.append("--skip-column-names")
    cmd = mysql_cmd(conn, extra + ["-e", sql])
    cmd = mysql_cmd(conn, extra)
    proc = subprocess.run(
        cmd,
        input=sql,
        text=True,
        capture_output=True,
        env=mysql_env(conn),
全局存储体系.md
@@ -47,11 +47,14 @@
|---|---|---|
| `a_share_daily_price` | 默认 A 股前复权日线 K 线 | 当前默认日线主表 |
| `a_share_minute_price` | A 股分钟 K 线 | 当前默认分钟线主表,体量最大 |
| `a_share_minute_price_full_adj` | A 股全复权 1 分钟 K 线 | 新增全复权分钟线公共表;不替代默认分钟线,查询必须带 `trade_date + symbol + trade_time` 边界 |
| `a_share_daily_front_adj_missing_ohlc_20230101_20260508` | 前复权源包中停牌 / 无 OHLC 行审计 | 不能补价进默认 K 线表 |
| `a_share_daily_price_backup_before_front_adj_20260523_1808` | 前复权切换前旧日线备份 | 只用于追溯旧口径 |
| `a_share_daily_price_front_sync` | 前复权日线同步增量 / 影子表 | 用于同步和补数审计,不替代默认主表 |
| `a_share_minute_price_front_sync` | 前复权分钟线同步增量 / 影子表 | 用于同步和补数审计,不替代默认主表 |
| `a_share_kline_front_sync_run` | K 线同步运行记录 | 用于追踪同步批次、行数和状态 |
| `a_share_minute_full_adj_import_run` | 全复权分钟线导入批次 | 记录 `full_adj_minute_20260614_rar` 等导入批次、文件数、行数和日期范围 |
| `a_share_minute_full_adj_import_file_log` | 全复权分钟线文件级导入日志 | 记录每个源 CSV 的市场、代码、文件大小、入库行数;0 字节源文件在此表留痕 |
### 4.2 A 股基础维表和元数据表
@@ -172,3 +175,4 @@
## 9. 变更记录
- 2026-06-03:首次建立全局存储体系文档;根据本机 MySQL `tianxia` 的 `information_schema`、数据库索引文档和 stock-data 文件镜像整理当前公共表边界。
- 2026-06-14:新增全复权 1 分钟 K 线公共表 `a_share_minute_price_full_adj`,来源为 `D:\A股日级行情数据近两年2023csv.rar`;导入批次 `full_adj_minute_20260614_rar`,3161 个 CSV 已处理,有效入库 422,373,172 行,非空日期范围 `2023-03-24` 到 `2026-06-12`;详见 `data/全复权分钟线导入说明.md`。
全局数据格式.md
@@ -117,6 +117,66 @@
| `sync_run_id` | `varchar(96)` | indexed | 同步运行 ID |
| `synced_at` | `timestamp` | auto update | 同步写入时间 |
### `a_share_minute_price_full_adj`
A 股全复权 1 分钟 K 线公共表。该表是全复权口径,不替代默认分钟线主表 `a_share_minute_price`,也不与前复权同步影子表混用。
| 字段 | 类型 | 约束 | 含义 |
|---|---|---|---|
| `trade_date` | `date` | PK | 交易日 |
| `trade_time` | `time` | PK | 分钟时间 |
| `bar_time` | `datetime` | indexed | 完整 bar 时间 |
| `symbol` | `char(9)` | PK | 股票代码,形如 `600000.SH`、`000001.SZ`、`920000.BJ` |
| `market` | `varchar(8)` | not null | 市场,`SH` / `SZ` / `BJ` |
| `open_price` | `decimal(14,4)` | nullable | 全复权开盘价 |
| `high_price` | `decimal(14,4)` | nullable | 全复权最高价 |
| `low_price` | `decimal(14,4)` | nullable | 全复权最低价 |
| `close_price` | `decimal(14,4)` | nullable | 全复权收盘价 |
| `volume` | `decimal(24,4)` | nullable | 源成交量 |
| `amount` | `decimal(24,4)` | nullable | 源成交额 |
| `source_file` | `varchar(255)` | not null | 解压后相对源文件路径 |
| `source_archive` | `varchar(255)` | not null | 来源压缩包路径 |
| `import_run_id` | `varchar(96)` | indexed | 导入批次 |
| `imported_at` | `timestamp` | auto | 入库时间 |
主键:`symbol + trade_date + trade_time`。
查询约束:必须带 `trade_date`、`symbol`,最好同时限制 `trade_time` 范围;全表统计优先读 `a_share_minute_full_adj_import_run` 和 `a_share_minute_full_adj_import_file_log`。
### `a_share_minute_full_adj_import_run`
全复权分钟线导入批次记录表。
| 字段 | 类型 | 约束 | 含义 |
|---|---|---|---|
| `run_id` | `varchar(96)` | PK | 导入批次 ID |
| `started_at` / `finished_at` | `datetime` | indexed / nullable | 开始和结束时间 |
| `status` | `varchar(32)` | indexed | 运行状态 |
| `source_archive` | `varchar(512)` | not null | 来源压缩包 |
| `source_root` | `varchar(512)` | not null | 解压根目录 |
| `files_total` / `files_loaded` | `int` | not null | 文件总数和已处理文件数 |
| `rows_loaded` | `bigint` | not null | 有效入库行数 |
| `min_trade_date` / `max_trade_date` | `date` | nullable | 非空数据日期范围 |
| `error_message` | `text` | nullable | 失败信息 |
### `a_share_minute_full_adj_import_file_log`
全复权分钟线文件级导入日志。
| 字段 | 类型 | 约束 | 含义 |
|---|---|---|---|
| `id` | `bigint` | PK auto_increment | 日志 ID |
| `run_id` | `varchar(96)` | indexed | 导入批次 |
| `symbol` | `char(9)` | indexed | 股票代码 |
| `market` | `varchar(8)` | indexed | 市场 |
| `source_file` | `varchar(512)` | unique with run | 源文件相对路径 |
| `file_size` | `bigint` | not null | 源文件大小 |
| `rows_loaded` | `bigint` | not null | 该文件入库行数;0 表示源文件为空或无有效行 |
| `started_at` / `finished_at` | `datetime` | not null | 文件处理时间 |
| `duration_ms` | `bigint` | not null | 文件处理耗时 |
| `status` | `varchar(32)` | indexed | 文件处理状态 |
| `error_message` | `text` | nullable | 文件级错误 |
### `a_share_kline_front_sync_run`
K 线同步运行记录。
@@ -415,3 +475,4 @@
## 11. 变更记录
- 2026-06-03:首次建立全局数据格式文档;根据本机 MySQL `information_schema`、数据库索引文档和 stock-data 脚本整理公共表字段。
- 2026-06-14:新增 `a_share_minute_price_full_adj`、`a_share_minute_full_adj_import_run`、`a_share_minute_full_adj_import_file_log` 的字段 schema,登记全复权 1 分钟 K 线公共表和导入审计表。
管理执行日志.md
New file
@@ -0,0 +1,140 @@
# 管理执行日志
## 2026-06-16 16:26:30 MGMT-DS-20260616-KLINE-SYNC
关联事项:全局行情数据同步
执行人员:management
动作类型:数据同步
执行目标:使用 ds 同步 2026-06-16 可用的 A 股前复权 K 线数据到本地全局数据库。
执行过程:
1. 读取 ds 技能说明,确认同步脚本 `scripts/kline_front_incremental_sync.py` 可用并通过 `py_compile`。
2. 查询源端与本地覆盖范围,确认源端日线已有 `2026-06-16`,源端分钟线覆盖表最新为 `2026-06-12`,`2026-06-16` 分钟线覆盖行数为 `0`。
3. 执行日线同步 run_id=`ds_daily_sync_20260616_162459`,从 `2026-06-11` 同步到 `2026-06-16`。
4. 同步后校验本地主表 `a_share_daily_price` 在 `2026-06-16` 有 `5513` 行;镜像表本次 run 写入 `22044` 行。
使用命令或 skill:`ds`;`python scripts/kline_front_incremental_sync.py --run-id ds_daily_sync_20260616_162459 --periods 1d --append-to-main`
关键输出:
- 日线源行数:`22044`
- 日线镜像写入行数:`22044`
- 日线主表追加行数:`22044`
- 本地 `2026-06-16` 日线主表行数:`5513`
- 源端 `2026-06-16` 分钟线覆盖行数:`0`
- 源端分钟线覆盖表最新日期:`2026-06-12`
自检结果:日线同步完成并通过本地行数校验;分钟线因源端尚无 `2026-06-16` 覆盖数据,本次未同步。
异常 / 偏离:源端分钟线未提供 `2026-06-16` 数据,不触发外部 HTTP 补数任务,不写外部数据库。
当前状态:部分完成
## 2026-06-19 16:25:00 MGMT-DS-20260619-KLINE-SYNC
关联事项:全局行情数据同步
执行人员:management
动作类型:数据同步 / 脚本修复
执行目标:使用 ds 同步截至 2026-06-19 源端可用的 A 股前复权日线与分钟线数据到本地全局数据库。
执行过程:
1. 读取 ds 技能说明,确认 `scripts/kline_front_incremental_sync.py` 可用并通过 `py_compile`。
2. 查询覆盖范围:源端日线最新为 `2026-06-18`,源端 `2026-06-19` 日线行数为 `0`;源端分钟线覆盖表最新为 `2026-06-17`,`2026-06-19` 分钟线覆盖行数为 `0`。
3. 执行日线同步 run_id=`ds_daily_sync_20260619_155322`,从 `2026-06-17` 同步到 `2026-06-18`。
4. 分钟线先执行 `2026-04-21`,数据已落镜像表和主表各 `1324777` 行;收尾写 run log 时触发 Windows 命令行长度限制。
5. 修复 `scripts/kline_front_incremental_sync.py` 的 MySQL 调用方式:长 SQL 改为 stdin 输入,避免 `-e <large sql>` 触发命令行长度限制。
6. 补齐 `2026-04-21` run_id=`ds_minute_sync_20260421_155345` 的状态为 `SUCCESS`。
7. 使用优化参数完成 `2026-04-22` 分钟线同步,run_id=`ds_minute_sync_20260422_161255`,写入和追加 `1324777` 行。
8. 新增并启动后台分日补齐脚本 `scripts/ds_minute_backfill.ps1`,从 `2026-04-23` 到 `2026-06-17` 按交易日继续同步,日志目录为 `data/result/stat/ds_minute_backfill_20260619_r2`。
使用命令或 skill:`ds`;`python scripts/kline_front_incremental_sync.py --periods 1d --append-to-main`;`python scripts/kline_front_incremental_sync.py --periods 1m --minute-max-minutes-per-batch 120 --minute-symbols-per-batch 200 --append-to-main`;`scripts/ds_minute_backfill.ps1`
关键输出:
- 日线 run_id:`ds_daily_sync_20260619_155322`
- 日线同步范围:`2026-06-17` 至 `2026-06-18`
- 日线源行数 / 镜像写入 / 主表追加:`11016 / 11016 / 11016`
- 分钟线已完成日期:`2026-04-21`、`2026-04-22`
- 分钟线后台待补日期数:`37`
- 分钟线后台 PID:`51640`
- 分钟线后台日志目录:`data/result/stat/ds_minute_backfill_20260619_r2`
自检结果:日线已同步到源端最新;分钟线因缺口约 `51690549` 行,已转入后台分日任务。源端尚无 `2026-06-19` 日线和分钟线数据。
异常 / 偏离:`2026-04-21` 分钟线 run log 首次收尾因 Windows 命令行长度限制失败;已修复脚本并手工恢复该 run 的成功状态。未写外部数据库,未触发外部 HTTP 补数。
当前状态:部分完成,分钟线后台同步中
## 2026-06-23 04:10:00 MGMT-DS-20260623-KLINE-SYNC
关联事项:全局行情数据同步
执行人员:management
动作类型:数据同步
执行目标:使用 ds 同步截至 2026-06-23 源端可用的 A 股前复权 K 线数据到本地全局数据库。
执行过程:
1. 读取 ds 技能说明,确认 `scripts/kline_front_incremental_sync.py` 可用并通过 `py_compile`。
2. 查询覆盖范围:源端日线最新为 `2026-06-22`,源端 `2026-06-23` 日线行数为 `0`;源端分钟线覆盖表最新为 `2026-06-17`,`2026-06-17` 之后至 `2026-06-23` 覆盖行数为 `0`。
3. 执行日线同步 run_id=`ds_daily_sync_20260623_040911`,从 `2026-06-19` 同步到 `2026-06-22`。
4. 同步后校验本地主表 `a_share_daily_price` 在 `2026-06-22` 有 `5510` 行,本地主表最大日线日期为 `2026-06-22`。
使用命令或 skill:`ds`;`python scripts/kline_front_incremental_sync.py --run-id ds_daily_sync_20260623_040911 --periods 1d --append-to-main`
关键输出:
- 日线同步范围:`2026-06-19` 至 `2026-06-22`
- 日线源行数 / 镜像写入 / 主表追加:`5510 / 5510 / 5510`
- 本地 `2026-06-22` 日线主表行数:`5510`
- 源端分钟线覆盖表最新日期:`2026-06-17`
- 源端 `2026-06-17` 之后至 `2026-06-23` 分钟线覆盖行数:`0`
自检结果:日线已同步到源端最新;分钟线源端无新增数据,本次未执行分钟线写入。
异常 / 偏离:源端尚无 `2026-06-23` 日线数据,也无 `2026-06-17` 之后的分钟线覆盖数据。未写外部数据库,未触发外部 HTTP 补数。
当前状态:完成源端可用范围同步
## 2026-06-23 20:46:00 MGMT-DS-20260623-KLINE-SYNC-2
关联事项:全局行情数据同步
执行人员:management
动作类型:数据同步
执行目标:再次使用 ds 检查并同步 2026-06-23 当日源端新增的 A 股前复权 K 线数据。
执行过程:
1. 读取 ds 技能说明,确认 `scripts/kline_front_incremental_sync.py` 可用并通过 `py_compile`。
2. 查询覆盖范围:源端日线最新已更新为 `2026-06-23`,源端 `2026-06-23` 日线行数为 `5513`;源端分钟线覆盖表最新仍为 `2026-06-17`,`2026-06-17` 之后至 `2026-06-23` 覆盖行数为 `0`。
3. 执行日线同步 run_id=`ds_daily_sync_20260623_204520`,同步 `2026-06-23`。
4. 同步后校验本地主表 `a_share_daily_price` 在 `2026-06-23` 有 `5513` 行,本地主表最大日线日期为 `2026-06-23`。
使用命令或 skill:`ds`;`python scripts/kline_front_incremental_sync.py --run-id ds_daily_sync_20260623_204520 --periods 1d --append-to-main`
关键输出:
- 日线同步范围:`2026-06-23` 至 `2026-06-23`
- 日线源行数 / 镜像写入 / 主表追加:`5513 / 5513 / 5513`
- 本地 `2026-06-23` 日线主表行数:`5513`
- 源端分钟线覆盖表最新日期:`2026-06-17`
- 源端 `2026-06-17` 之后至 `2026-06-23` 分钟线覆盖行数:`0`
自检结果:日线已同步到源端最新;分钟线源端无新增数据,本次未执行分钟线写入。
异常 / 偏离:未写外部数据库,未触发外部 HTTP 补数。
当前状态:完成源端可用范围同步