小隐的博客

人生在世,笑饮一生
  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

AI量化qlib学习笔记二:转换数据

Posted on 2025-08-09 16:30  隐客  阅读(130)  评论(0)    收藏  举报

这个步骤是把csv数据转成qlib的bin数据,坑巨多。

之前说到放弃,就是因为它对分时小周期数据的支持非常不友好,懒得说了,直接上源码。

  1 #!/usr/bin/env python3
  2 # -*- coding: utf-8 -*-
  3 """
  4 简单的CSV转qlib工具 - 循环处理不同周期
  5 """
  6 
  7 import os
  8 import pandas as pd
  9 from pathlib import Path
 10 import subprocess
 11 import sys
 12 import tempfile
 13 import shutil
 14 from datetime import datetime, timedelta
 15 
 16 def load_trading_calendar():
 17     """加载交易日历"""
 18     calendar_file = Path(__file__).parent / "day.txt"
 19     
 20     if not calendar_file.exists():
 21         print(f"⚠ 交易日历文件不存在: {calendar_file}")
 22         return None
 23     
 24     try:
 25         # 读取交易日历,假设格式为每行一个日期 YYYY-MM-DD
 26         with open(calendar_file, 'r', encoding='utf-8') as f:
 27             dates = []
 28             for line in f:
 29                 line = line.strip()
 30                 if line and not line.startswith('#'):  # 跳过空行和注释
 31                     try:
 32                         date_obj = datetime.strptime(line, '%Y-%m-%d').date()
 33                         dates.append(date_obj)
 34                     except ValueError:
 35                         continue
 36         
 37         dates.sort()  # 确保日期排序
 38         print(f"✓ 加载交易日历: {len(dates)} 个交易日")
 39         return dates
 40         
 41     except Exception as e:
 42         print(f"✗ 读取交易日历失败: {e}")
 43         return None
 44 
 45 def get_previous_trading_date(current_date, trading_calendar):
 46     """获取指定日期的前一个交易日"""
 47     if not trading_calendar:
 48         return current_date - timedelta(days=1)  # 如果没有日历,简单减一天
 49     
 50     try:
 51         # 找到当前日期在交易日历中的位置
 52         if current_date in trading_calendar:
 53             current_index = trading_calendar.index(current_date)
 54             if current_index > 0:
 55                 return trading_calendar[current_index - 1]
 56         
 57         # 如果当前日期不在交易日历中,找到最近的前一个交易日
 58         for i in range(len(trading_calendar) - 1, -1, -1):
 59             if trading_calendar[i] < current_date:
 60                 return trading_calendar[i]
 61         
 62         # 如果找不到,返回简单减一天的结果
 63         return current_date - timedelta(days=1)
 64         
 65     except Exception as e:
 66         print(f"⚠ 获取前一交易日失败: {e}")
 67         return current_date - timedelta(days=1)
 68 
 69 def adjust_night_session_time(df, trading_calendar):
 70     """调整夜盘时间:将21:00-23:59的数据日期改为前一个交易日"""
 71     if 'datetime' not in df.columns:
 72         return df
 73     
 74     print("  检查夜盘时间...")
 75     
 76     # 转换datetime列为pandas datetime类型
 77     df['datetime'] = pd.to_datetime(df['datetime'])
 78     
 79     adjusted_count = 0
 80     
 81     for idx, row in df.iterrows():
 82         dt = row['datetime']
 83         hour = dt.hour
 84         
 85         # 检查是否为夜盘时间 (21:00-23:59)
 86         if 21 <= hour <= 23:
 87             current_date = dt.date()
 88             previous_trading_date = get_previous_trading_date(current_date, trading_calendar)
 89             
 90             # 创建新的datetime,保持时间不变,只改日期
 91             new_datetime = datetime.combine(previous_trading_date, dt.time())
 92             df.at[idx, 'datetime'] = new_datetime
 93             adjusted_count += 1
 94     
 95     if adjusted_count > 0:
 96         print(f"  ✓ 调整了 {adjusted_count} 条夜盘数据的日期")
 97         # 重新按时间排序
 98         df = df.sort_values('datetime').reset_index(drop=True)
 99     else:
100         print("  - 没有发现需要调整的夜盘数据")
101     
102     return df
103 
104 def run_dump_bin_ordered(temp_csv_dir, target_path, freq, ordered_symbols):
105     """按指定顺序运行qlib的dump_bin.py脚本,第一个用dump_all,后续用dump_update"""
106     dump_script_path = Path(r'C:\ctp\q_qlib\qlib_src\scripts\dump_bin.py')
107     
108     if not dump_script_path.exists():
109         print(f"✗ dump_bin.py脚本不存在: {dump_script_path}")
110         return False
111     
112     print(f"使用dump_bin.py按顺序转换{freq}数据...")
113     print(f"处理顺序: {ordered_symbols}")
114     
115     # 按顺序处理每个品种
116     for i, symbol in enumerate(ordered_symbols):
117         print(f"  处理 {i+1}/{len(ordered_symbols)}: {symbol}")
118         
119         # 查找该品种的CSV文件
120         csv_files = list(Path(temp_csv_dir).glob(f"{symbol}.*.csv"))
121         
122         if not csv_files:
123             print(f"    ⚠ 未找到 {symbol} 的文件")
124             continue
125         
126         # 为该品种创建单独的临时目录
127         symbol_temp_dir = Path(temp_csv_dir) / f"temp_{symbol}"
128         symbol_temp_dir.mkdir(exist_ok=True)
129         
130         # 复制该品种的文件到单独目录
131         for csv_file in csv_files:
132             shutil.copy2(csv_file, symbol_temp_dir / csv_file.name)
133         
134         # 决定使用dump_all还是dump_update
135         dump_mode = "dump_all" if  i==0   else "dump_update"
136         
137         cmd = [
138             sys.executable, str(dump_script_path),
139             dump_mode,
140             "--csv_path", str(symbol_temp_dir),  # 传递该品种的目录
141             "--qlib_dir", str(target_path),
142             "--freq", freq,
143             "--max_workers", "1",  # 单线程确保顺序
144             "--include_fields", "open,close,high,low,volume",
145             "--date_field_name", "datetime" 
146         ]
147         
148         try:
149             result = subprocess.run(cmd, capture_output=True, text=True)
150             
151             if result.returncode == 0:
152                 print(f"    ✓ {symbol} 转换成功 ({dump_mode})")
153             else:
154                 print(f"    ✗ {symbol} 转换失败 ({dump_mode})")
155                 print(f"    错误: {result.stderr}")
156                 # 清理临时目录
157                 shutil.rmtree(symbol_temp_dir, ignore_errors=True)
158                 return False
159                 
160         except Exception as e:
161             print(f"    ✗ 处理 {symbol} 时出错: {e}")
162             # 清理临时目录
163             shutil.rmtree(symbol_temp_dir, ignore_errors=True)
164             return False
165         
166         # 清理该品种的临时目录
167         shutil.rmtree(symbol_temp_dir, ignore_errors=True)
168     
169     print(f"✓ 所有品种按顺序转换完成")
170     return True
171 
172 def run_dump_bin_ordered_update(temp_csv_dir, target_path, freq, ordered_symbols):
173     """按指定顺序运行qlib的dump_bin.py脚本,第一个用dump_all,后续用dump_update(用于分钟周期)"""
174     dump_script_path = Path(r'C:\ctp\q_qlib\qlib_src\scripts\dump_bin.py')
175     
176     if not dump_script_path.exists():
177         print(f"✗ dump_bin.py脚本不存在: {dump_script_path}")
178         return False
179     
180     print(f"使用dump_bin.py按顺序转换{freq}数据(第一个dump_all,后续dump_update)...")
181     print(f"处理顺序: {ordered_symbols}")
182     
183     # 按顺序处理每个品种
184     for i, symbol in enumerate(ordered_symbols):
185         print(f"  处理 {i+1}/{len(ordered_symbols)}: {symbol}")
186         
187         # 查找该品种的CSV文件
188         csv_files = list(Path(temp_csv_dir).glob(f"{symbol}.*.csv"))
189         
190         if not csv_files:
191             print(f"    ⚠ 未找到 {symbol} 的文件")
192             continue
193         
194         # 为该品种创建单独的临时目录
195         symbol_temp_dir = Path(temp_csv_dir) / f"temp_{symbol}"
196         symbol_temp_dir.mkdir(exist_ok=True)
197         
198         # 复制该品种的文件到单独目录
199         for csv_file in csv_files:
200             shutil.copy2(csv_file, symbol_temp_dir / csv_file.name)
201         
202         # 第一个品种使用dump_all,后续使用dump_update
203         dump_mode = "dump_all" if i == 0 else "dump_update"
204         
205         cmd = [
206             sys.executable, str(dump_script_path),
207             dump_mode,
208             "--csv_path", str(symbol_temp_dir),  # 传递该品种的目录
209             "--qlib_dir", str(target_path),
210             "--freq", freq,
211             "--max_workers", "1",  # 单线程确保顺序
212             "--include_fields", "open,close,high,low,volume",
213             "--date_field_name", "datetime" 
214         ]
215         
216         try:
217             result = subprocess.run(cmd, capture_output=True, text=True)
218             
219             if result.returncode == 0:
220                 print(f"    ✓ {symbol} 转换成功 ({dump_mode})")
221             else:
222                 print(f"    ✗ {symbol} 转换失败 ({dump_mode})")
223                 print(f"    错误: {result.stderr}")
224                 # 清理临时目录
225                 shutil.rmtree(symbol_temp_dir, ignore_errors=True)
226                 return False
227                 
228         except Exception as e:
229             print(f"    ✗ 处理 {symbol} 时出错: {e}")
230             # 清理临时目录
231             shutil.rmtree(symbol_temp_dir, ignore_errors=True)
232             return False
233         
234         # 清理该品种的临时目录
235         shutil.rmtree(symbol_temp_dir, ignore_errors=True)
236     
237     print(f"✓ 所有品种按顺序转换完成")
238     return True
239 
240 def run_dump_bin_group(temp_csv_dir, target_path, freq, dump_mode, symbols):
241     """运行qlib的dump_bin.py脚本处理一组相同交易时间的合约"""
242     dump_script_path = Path(r'C:\ctp\q_qlib\qlib_src\scripts\dump_bin.py')
243     
244     if not dump_script_path.exists():
245         print(f"✗ dump_bin.py脚本不存在: {dump_script_path}")
246         return False
247     
248     print(f"      使用{dump_mode}模式处理: {symbols}")
249     
250     # 检查临时目录中的文件
251     temp_files = list(Path(temp_csv_dir).glob("*.csv"))
252     print(f"      目录中有 {len(temp_files)} 个CSV文件")
253     
254     cmd = [
255         sys.executable, str(dump_script_path),
256         dump_mode,
257         "--csv_path", str(temp_csv_dir),
258         "--qlib_dir", str(target_path),
259         "--freq", freq,
260         "--max_workers", "1",
261         "--include_fields", "open,close,high,low,volume",
262         "--date_field_name", "datetime" 
263     ]
264     
265     try:
266         result = subprocess.run(cmd, capture_output=True, text=True)
267         
268         if result.returncode == 0:
269             print(f"      ✓ 转换成功")
270             return True
271         else:
272             print(f"      ✗ 转换失败")
273             print(f"      错误: {result.stderr}")
274             return False
275             
276     except Exception as e:
277         print(f"      ✗ 运行dump_bin.py时出错: {e}")
278         return False
279 
280 def run_dump_bin(temp_csv_dir, target_path, freq):
281     """运行qlib的dump_bin.py脚本"""
282     dump_script_path = Path(r'C:\ctp\q_qlib\qlib_src\scripts\dump_bin.py')
283     
284     if not dump_script_path.exists():
285         print(f"✗ dump_bin.py脚本不存在: {dump_script_path}")
286         return False
287     
288     print(f"使用dump_bin.py转换{freq}数据...")
289     
290     # 检查临时目录中的文件
291     temp_files = list(Path(temp_csv_dir).glob("*.csv"))
292     print(f"  临时目录中有 {len(temp_files)} 个CSV文件")
293     for f in temp_files[:3]:  # 只显示前3个
294         print(f"    - {f.name}")
295     if len(temp_files) > 3:
296         print(f"    ... 还有 {len(temp_files) - 3} 个文件")
297     
298     cmd = [
299         sys.executable, str(dump_script_path),
300         "dump_all",
301         "--csv_path", str(temp_csv_dir),
302         "--qlib_dir", str(target_path),
303         "--freq", freq,  # 使用传入的频率参数
304         "--max_workers", "1",  # 改为单线程,便于调试
305         "--include_fields", "open,close,high,low,volume",
306         "--date_field_name", "datetime" 
307     ]
308     
309     print(f"  执行命令: {' '.join(cmd)}")
310     
311     try:
312         result = subprocess.run(cmd, capture_output=True, text=True)
313         
314         print(f"  返回码: {result.returncode}")
315         
316         if result.stdout:
317             print(f"  标准输出:")
318             for line in result.stdout.split('\n')[:10]:  # 只显示前10行
319                 if line.strip():
320                     print(f"    {line}")
321         
322         if result.stderr:
323             print(f"  错误输出:")
324             for line in result.stderr.split('\n')[:10]:  # 只显示前10行
325                 if line.strip():
326                     print(f"    {line}")
327         
328         if result.returncode == 0:
329             print(f"  ✓ 数据转换成功")
330             return True
331         else:
332             print(f"  ✗ 数据转换失败 (返回码: {result.returncode})")
333             return False
334             
335     except Exception as e:
336         print(f"✗ 运行dump_bin.py时出错: {e}")
337         return False
338 
339 def copy_symbol_period_files(source_dir, temp_dir, symbol, period, trading_calendar=None):
340     """复制指定品种和周期的文件到临时目录"""
341     source_path = Path(source_dir)
342     temp_path = Path(temp_dir)
343     temp_path.mkdir(parents=True, exist_ok=True)
344     
345     copied_count = 0
346     
347     # 查找指定品种和周期的文件
348     pattern = f"{symbol}.*.{period}.csv"
349     for csv_file in source_path.glob(pattern):
350         try:
351             print(f"    处理文件: {csv_file.name}")
352             
353             # 读取CSV文件
354             df = pd.read_csv(csv_file, encoding='utf-8')
355             
356             # 解析文件名:RBL8.SHFE.day.csv
357             filename = csv_file.stem  # 去掉.csv
358             parts = filename.split('.')
359             
360             if len(parts) >= 3:
361                 file_symbol = parts[0].upper()
362                 exchange = parts[1]
363                 
364                 # 添加instrument列
365                 df['instrument'] = file_symbol
366                 
367                 # 调整夜盘时间(只对分钟级数据进行调整)
368                 if period in ['1m', '5m', '15m', '30m', '60m'] and trading_calendar:
369                     df = adjust_night_session_time(df, trading_calendar)
370                 
371                 # 重新排列列顺序
372                 cols = ['instrument', 'datetime'] + [col for col in df.columns if col not in ['instrument', 'datetime']]
373                 df = df[cols]
374                 
375                 # 保存为标准格式:RBL8.SHFE.csv (去掉周期)
376                 new_filename = f"{file_symbol}.{exchange}.csv"
377                 output_file = temp_path / new_filename
378                 df.to_csv(output_file, index=False)
379                 
380                 print(f"    ✓ 完成: {csv_file.name} -> {new_filename}")
381                 copied_count += 1
382                 
383         except Exception as e:
384             print(f"    ✗ 处理文件 {csv_file} 时出错: {e}")
385     
386     return copied_count
387 
388 def copy_period_files(source_dir, temp_dir, period, trading_calendar=None):
389     """复制指定周期的文件到临时目录,并修正夜盘时间"""
390     source_path = Path(source_dir)
391     temp_path = Path(temp_dir)
392     temp_path.mkdir(parents=True, exist_ok=True)
393     
394     copied_count = 0
395     
396     # 查找指定周期的文件
397     pattern = f"*.{period}.csv"
398     for csv_file in source_path.glob(pattern):
399         try:
400             print(f"  处理文件: {csv_file.name}")
401             
402             # 读取CSV文件
403             df = pd.read_csv(csv_file, encoding='utf-8')
404             
405             # 解析文件名:RBL8.SHFE.day.csv
406             filename = csv_file.stem  # 去掉.csv
407             parts = filename.split('.')
408             
409             if len(parts) >= 3:
410                 symbol = parts[0].upper()
411                 exchange = parts[1]
412                 
413                 # 添加instrument列
414                 df['instrument'] = symbol
415                 
416                 # 调整夜盘时间(只对分钟级数据进行调整)
417                 if period in ['1m', '5m', '15m', '30m', '60m'] and trading_calendar:
418                     df = adjust_night_session_time(df, trading_calendar)
419                 
420                 # 重新排列列顺序
421                 cols = ['instrument', 'datetime'] + [col for col in df.columns if col not in ['instrument', 'datetime']]
422                 df = df[cols]
423                 
424                 # 保存为标准格式:RBL8.SHFE.csv (去掉周期)
425                 new_filename = f"{symbol}.{exchange}.csv"
426                 output_file = temp_path / new_filename
427                 df.to_csv(output_file, index=False)
428                 
429                 print(f"  ✓ 完成: {csv_file.name} -> {new_filename}")
430                 copied_count += 1
431                 
432         except Exception as e:
433             print(f"  ✗ 处理文件 {csv_file} 时出错: {e}")
434     
435     return copied_count
436 
437 def run_dump_bin_contract(temp_csv_dir, target_path, freq, contract, period):
438     """为单个合约运行qlib的dump_bin.py脚本"""
439     dump_script_path = Path(r'C:\ctp\q_qlib\qlib_src\scripts\dump_bin.py')
440     
441     if not dump_script_path.exists():
442         print(f"      ✗ dump_bin.py脚本不存在: {dump_script_path}")
443         return False
444     
445     print(f"      使用dump_bin.py转换{freq}数据...")
446     
447     cmd = [
448         sys.executable, str(dump_script_path),
449         "dump_all",  # 每个合约都用dump_all,独立处理
450         "--csv_path", str(temp_csv_dir),
451         "--qlib_dir", str(target_path),
452         "--freq", freq,
453         "--max_workers", "1",
454         "--include_fields", "open,close,high,low,volume",
455         "--date_field_name", "datetime" 
456     ]
457     
458     try:
459         result = subprocess.run(cmd, capture_output=True, text=True)
460         
461         if result.returncode == 0:
462             print(f"      ✓ 转换成功")
463             return True
464         else:
465             print(f"      ✗ 转换失败")
466             if result.stderr:
467                 print(f"      错误: {result.stderr}")
468             return False
469             
470     except Exception as e:
471         print(f"      ✗ 运行dump_bin.py时出错: {e}")
472         return False
473 
474 def main():
475     """主函数 - 按合约为单位处理,每个合约独立的数据目录"""
476     # 配置
477     source_dir = r"C:\ctp\q_qlib\cleaned_data"
478     base_target_dir = r"C:\ctp\q_qlib\qlib_data\cn_data"
479     
480     # 定义要处理的周期和对应的qlib频率
481     period_freq_mapping = {
482         'day': 'day',
483         '1m': '1min',
484         '5m': '5min',
485         '15m': '15min',
486         '30m': '30min',
487         '60m': '60min'
488     }
489     
490     # 调整处理顺序:day放到最后,让all.txt时间周期更长
491     periods = ['1m', '5m', '15m', '30m', '60m', 'day']
492     
493     print("=== 按合约为单位处理数据 ===")
494     print(f"源目录: {source_dir}")
495     print(f"目标目录: {base_target_dir}")
496     print(f"处理周期: {periods} (day放在最后,让all.txt时间周期更长)")
497     
498     # 检查源目录
499     if not os.path.exists(source_dir):
500         print(f"✗ 源目录不存在: {source_dir}")
501         return
502     
503     # 先检查源目录中实际存在的文件
504     print(f"\n检查源目录中的文件...")
505     source_path = Path(source_dir)
506     all_files = list(source_path.glob("*.csv"))
507     print(f"找到 {len(all_files)} 个CSV文件")
508     
509     # 加载交易日历
510     print("\n加载交易日历...")
511     trading_calendar = load_trading_calendar()
512     if trading_calendar:
513         print(f"交易日历范围: {trading_calendar[0]} 到 {trading_calendar[-1]}")
514     else:
515         print("⚠ 未加载交易日历,夜盘时间将使用简单日期减1的方式处理")
516     
517     # 创建目标目录
518     Path(base_target_dir).mkdir(parents=True, exist_ok=True)
519     
520     # 获取所有合约(从实际存在的文件中)
521     contract_files = {}  # {合约名: {周期: [文件列表]}}
522     
523     for csv_file in all_files:
524         filename = csv_file.stem
525         parts = filename.split('.')
526         if len(parts) >= 3:
527             contract = f"{parts[0].upper()}.{parts[1]}"  # 如 RBL8.SHFE
528             period = parts[2]  # 如 day, 1m
529             
530             if contract not in contract_files:
531                 contract_files[contract] = {}
532             if period not in contract_files[contract]:
533                 contract_files[contract][period] = []
534             contract_files[contract][period].append(csv_file)
535     
536     print(f"\n发现 {len(contract_files)} 个合约:")
537     for contract in sorted(contract_files.keys()):
538         available_periods = list(contract_files[contract].keys())
539         print(f"  {contract}: {available_periods}")
540     
541     # 按合约处理
542     processed_contracts = 0
543     
544     for contract in sorted(contract_files.keys()):
545         print(f"\n{'='*80}")
546         print(f"处理合约: {contract}")
547         print(f"{'='*80}")
548         
549         # 为该合约创建独立的目标目录
550         contract_target_dir = Path(base_target_dir) / contract
551         contract_target_dir.mkdir(parents=True, exist_ok=True)
552         
553         print(f"合约数据目录: {contract_target_dir}")
554         
555         # 处理该合约的所有周期
556         contract_success = True
557         
558         for period in periods:
559             if period not in contract_files[contract]:
560                 print(f"  ⚠ 跳过 {period} 周期:没有找到相关文件")
561                 continue
562             
563             qlib_freq = period_freq_mapping[period]
564             print(f"\n  处理周期: {period} (qlib频率: {qlib_freq})")
565             
566             # 创建临时目录
567             with tempfile.TemporaryDirectory() as temp_dir:
568                 print(f"    使用临时目录: {temp_dir}")
569                 
570                 # 复制该合约该周期的文件
571                 copied_count = 0
572                 for csv_file in contract_files[contract][period]:
573                     try:
574                         print(f"      处理文件: {csv_file.name}")
575                         
576                         # 读取CSV文件
577                         df = pd.read_csv(csv_file, encoding='utf-8')
578                         
579                         # 解析文件名:RBL8.SHFE.day.csv
580                         filename = csv_file.stem
581                         parts = filename.split('.')
582                         symbol = parts[0].upper()
583                         exchange = parts[1]
584                         
585                         # 添加instrument列
586                         df['instrument'] = symbol
587                         
588                         # 调整夜盘时间(只对分钟级数据进行调整)
589                         if period in ['1m', '5m', '15m', '30m', '60m'] and trading_calendar:
590                             df = adjust_night_session_time(df, trading_calendar)
591                         
592                         # 重新排列列顺序
593                         cols = ['instrument', 'datetime'] + [col for col in df.columns if col not in ['instrument', 'datetime']]
594                         df = df[cols]
595                         
596                         # 保存为标准格式:RBL8.SHFE.csv (去掉周期)
597                         new_filename = f"{symbol}.{exchange}.csv"
598                         output_file = Path(temp_dir) / new_filename
599                         df.to_csv(output_file, index=False)
600                         
601                         print(f"      ✓ 完成: {csv_file.name} -> {new_filename}")
602                         copied_count += 1
603                         
604                     except Exception as e:
605                         print(f"      ✗ 处理文件 {csv_file} 时出错: {e}")
606                         contract_success = False
607                         break
608                 
609                 if copied_count == 0:
610                     print(f"    ✗ 没有成功复制任何文件")
611                     contract_success = False
612                     continue
613                 
614                 print(f"    复制了 {copied_count} 个文件")
615                 
616                 # 使用dump_all处理该合约该周期的数据
617                 if run_dump_bin_contract(temp_dir, contract_target_dir, qlib_freq, contract, period):
618                     print(f"    ✓ {period} 周期处理完成")
619                 else:
620                     print(f"    ✗ {period} 周期处理失败")
621                     contract_success = False
622         
623         if contract_success:
624             print(f"✓ 合约 {contract} 处理完成")
625             processed_contracts += 1
626         else:
627             print(f"✗ 合约 {contract} 处理失败")
628     
629     print(f"\n{'='*50}")
630     print(f"处理完成!成功处理了 {processed_contracts}/{len(contract_files)} 个合约")
631     print(f"数据路径: {base_target_dir}")
632     print(f"每个合约都有独立的数据目录,避免了时间对齐问题")
633     print(f"处理顺序: 分钟周期 → day周期,让all.txt时间周期更长")
634     print(f"夜盘时间修正功能已启用 (21:00-23:59 → 前一交易日)")
635     print(f"{'='*50}")
636 
637 
638 
639 if __name__ == "__main__":
640     main()
641     #python qlib_convert_to_qlib.py

 

QQ交流