cfquant 0.2.36__tar.gz → 0.2.38__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.
- {cfquant-0.2.36 → cfquant-0.2.38}/PKG-INFO +1 -1
- {cfquant-0.2.36 → cfquant-0.2.38}/cfquant/qmt_bridge.py +3 -1
- {cfquant-0.2.36 → cfquant-0.2.38}/cfquant/qmt_strategy_deploy.py +10 -12
- {cfquant-0.2.36 → cfquant-0.2.38}/cfquant/tests/test_qmt_strategy_deploy.py +11 -3
- {cfquant-0.2.36 → cfquant-0.2.38}/cfquant/tx_trade_bridge.py +4 -2
- {cfquant-0.2.36 → cfquant-0.2.38}/cfquant/version.py +2 -2
- {cfquant-0.2.36 → cfquant-0.2.38}/cfquant/xttype.py +60 -18
- {cfquant-0.2.36 → cfquant-0.2.38}/cfquant.egg-info/PKG-INFO +1 -1
- {cfquant-0.2.36 → cfquant-0.2.38}/pyproject.toml +1 -1
- {cfquant-0.2.36 → cfquant-0.2.38}/web_dashboard/app.js +45 -7
- {cfquant-0.2.36 → cfquant-0.2.38}/web_dashboard/index.html +2 -3
- {cfquant-0.2.36 → cfquant-0.2.38}/LICENSE +0 -0
- {cfquant-0.2.36 → cfquant-0.2.38}/LTtx/__init__.py +0 -0
- {cfquant-0.2.36 → cfquant-0.2.38}/LTtx/tx/Config.txt +0 -0
- {cfquant-0.2.36 → cfquant-0.2.38}/LTtx/tx/LTtx_server.py +0 -0
- {cfquant-0.2.36 → cfquant-0.2.38}/LTtx/tx/__init__.py +0 -0
- {cfquant-0.2.36 → cfquant-0.2.38}/LTtx/tx/tx.py +0 -0
- {cfquant-0.2.36 → cfquant-0.2.38}/MANIFEST.in +0 -0
- {cfquant-0.2.36 → cfquant-0.2.38}/README.md +0 -0
- {cfquant-0.2.36 → cfquant-0.2.38}/cfquant/__init__.py +0 -0
- {cfquant-0.2.36 → cfquant-0.2.38}/cfquant/_editable_install.py +0 -0
- {cfquant-0.2.36 → cfquant-0.2.38}/cfquant/account_routing.py +0 -0
- {cfquant-0.2.36 → cfquant-0.2.38}/cfquant/batch_orders.py +0 -0
- {cfquant-0.2.36 → cfquant-0.2.38}/cfquant/cftrader.py +0 -0
- {cfquant-0.2.36 → cfquant-0.2.38}/cfquant/channels.py +0 -0
- {cfquant-0.2.36 → cfquant-0.2.38}/cfquant/cli.py +0 -0
- {cfquant-0.2.36 → cfquant-0.2.38}/cfquant/client.py +0 -0
- {cfquant-0.2.36 → cfquant-0.2.38}/cfquant/config.py +0 -0
- {cfquant-0.2.36 → cfquant-0.2.38}/cfquant/hub.py +0 -0
- {cfquant-0.2.36 → cfquant-0.2.38}/cfquant/level2.py +0 -0
- {cfquant-0.2.36 → cfquant-0.2.38}/cfquant/log_management.py +0 -0
- {cfquant-0.2.36 → cfquant-0.2.38}/cfquant/logging_i18n.py +0 -0
- {cfquant-0.2.36 → cfquant-0.2.38}/cfquant/normal_bridge.py +0 -0
- {cfquant-0.2.36 → cfquant-0.2.38}/cfquant/order_meta.py +0 -0
- {cfquant-0.2.36 → cfquant-0.2.38}/cfquant/pipe_bridge.py +0 -0
- {cfquant-0.2.36 → cfquant-0.2.38}/cfquant/pipe_client.py +0 -0
- {cfquant-0.2.36 → cfquant-0.2.38}/cfquant/pipe_hub.py +0 -0
- {cfquant-0.2.36 → cfquant-0.2.38}/cfquant/pipe_transport.py +0 -0
- {cfquant-0.2.36 → cfquant-0.2.38}/cfquant/protocol.py +0 -0
- {cfquant-0.2.36 → cfquant-0.2.38}/cfquant/qmt_strategy_package.py +0 -0
- {cfquant-0.2.36 → cfquant-0.2.38}/cfquant/qmt_strategy_runtime.py +0 -0
- {cfquant-0.2.36 → cfquant-0.2.38}/cfquant/runtime_report.py +0 -0
- {cfquant-0.2.36 → cfquant-0.2.38}/cfquant/tests/10_/345/221/275/344/273/244/350/241/214/346/216/245/345/217/243/346/265/213/350/257/225.py" +0 -0
- {cfquant-0.2.36 → cfquant-0.2.38}/cfquant/tests/11_/346/231/256/351/200/232/346/241/245/346/216/245/346/264/276/345/217/221/346/265/213/350/257/225.py" +0 -0
- {cfquant-0.2.36 → cfquant-0.2.38}/cfquant/tests/12_/350/256/242/345/215/225/345/244/207/346/263/250/346/265/213/350/257/225.py" +0 -0
- {cfquant-0.2.36 → cfquant-0.2.38}/cfquant/tests/13_/347/256/241/351/201/223/344/270/255/345/277/203/350/277/236/346/216/245/346/265/213/350/257/225.py" +0 -0
- {cfquant-0.2.36 → cfquant-0.2.38}/cfquant/tests/14_/350/277/220/350/241/214/346/227/266/346/212/245/345/221/212/346/265/213/350/257/225.py" +0 -0
- {cfquant-0.2.36 → cfquant-0.2.38}/cfquant/tests/15_/347/275/221/351/241/265/347/212/266/346/200/201/347/274/223/345/255/230/346/265/213/350/257/225.py" +0 -0
- {cfquant-0.2.36 → cfquant-0.2.38}/cfquant/tests/16_/345/220/257/345/212/250/345/256/211/350/243/205/346/265/213/350/257/225.py" +0 -0
- {cfquant-0.2.36 → cfquant-0.2.38}/cfquant/tests/17_/345/244/247QMT/346/216/245/345/217/243/351/200/202/351/205/215/346/265/213/350/257/225.py" +0 -0
- {cfquant-0.2.36 → cfquant-0.2.38}/cfquant/tests/18_/351/253/230/347/272/247/346/250/241/345/274/217/345/256/236/346/234/272/350/201/224/350/260/203.py" +0 -0
- {cfquant-0.2.36 → cfquant-0.2.38}/cfquant/tests/19_/345/256/236/346/234/272/350/201/224/350/260/203/345/210/244/345/256/232/346/265/213/350/257/225.py" +0 -0
- {cfquant-0.2.36 → cfquant-0.2.38}/cfquant/tests/1_/350/241/214/346/203/205/346/216/245/346/224/266/346/265/213/350/257/225.py" +0 -0
- {cfquant-0.2.36 → cfquant-0.2.38}/cfquant/tests/20_/350/201/224/350/260/203/351/227/256/351/242/230/344/277/256/345/244/215/346/265/213/350/257/225.py" +0 -0
- {cfquant-0.2.36 → cfquant-0.2.38}/cfquant/tests/21_/345/215/225/350/202/241/350/241/214/346/203/205/350/256/242/351/230/205/346/265/213/350/257/225.py" +0 -0
- {cfquant-0.2.36 → cfquant-0.2.38}/cfquant/tests/22_/350/277/236/346/216/245/350/257/212/346/226/255/346/265/213/350/257/225.py" +0 -0
- {cfquant-0.2.36 → cfquant-0.2.38}/cfquant/tests/23_/347/244/272/344/276/213/351/205/215/347/275/256/346/265/213/350/257/225.py" +0 -0
- {cfquant-0.2.36 → cfquant-0.2.38}/cfquant/tests/24_/350/264/246/346/210/267/347/274/223/345/255/230/346/214/211/351/234/200/345/210/267/346/226/260/346/265/213/350/257/225.py" +0 -0
- {cfquant-0.2.36 → cfquant-0.2.38}/cfquant/tests/25_/350/264/246/346/210/267/347/274/223/345/255/230/351/241/265/351/235/242/346/265/213/350/257/225.py" +0 -0
- {cfquant-0.2.36 → cfquant-0.2.38}/cfquant/tests/26_/345/205/250/346/216/250/350/256/242/351/230/205/346/265/213/350/257/225.py" +0 -0
- {cfquant-0.2.36 → cfquant-0.2.38}/cfquant/tests/27_/345/205/250/346/216/250/350/256/242/351/230/205/351/241/265/351/235/242/346/265/213/350/257/225.py" +0 -0
- {cfquant-0.2.36 → cfquant-0.2.38}/cfquant/tests/28_Level2/346/216/245/345/217/243/351/200/202/351/205/215/346/265/213/350/257/225.py" +0 -0
- {cfquant-0.2.36 → cfquant-0.2.38}/cfquant/tests/29_Level2/350/241/214/346/203/205/346/265/213/350/257/225.py" +0 -0
- {cfquant-0.2.36 → cfquant-0.2.38}/cfquant/tests/2_/346/225/260/346/215/256/350/216/267/345/217/226/346/265/213/350/257/225.py" +0 -0
- {cfquant-0.2.36 → cfquant-0.2.38}/cfquant/tests/30_cftrader/346/211/271/351/207/217/344/270/213/345/215/225/346/200/247/350/203/275/345/237/272/345/207/206.py" +0 -0
- {cfquant-0.2.36 → cfquant-0.2.38}/cfquant/tests/31_cftrader/346/250/241/346/213/237/350/264/246/345/217/267/346/211/271/351/207/217/344/270/213/345/215/225/346/265/213/350/257/225.py" +0 -0
- {cfquant-0.2.36 → cfquant-0.2.38}/cfquant/tests/32_/345/274/202/346/255/245/344/270/213/345/215/225/346/265/213/350/257/225.py" +0 -0
- {cfquant-0.2.36 → cfquant-0.2.38}/cfquant/tests/33_/345/220/214/346/255/245/344/270/213/345/215/225/345/233/236/350/260/203/346/265/213/350/257/225.py" +0 -0
- {cfquant-0.2.36 → cfquant-0.2.38}/cfquant/tests/3_/346/225/260/346/215/256/344/270/213/350/275/275/346/265/213/350/257/225.py" +0 -0
- {cfquant-0.2.36 → cfquant-0.2.38}/cfquant/tests/4_/344/272/244/346/230/223/345/247/224/346/211/230/346/237/245/350/257/242/346/265/213/350/257/225.py" +0 -0
- {cfquant-0.2.36 → cfquant-0.2.38}/cfquant/tests/5_/347/234/237/345/256/236/344/270/213/345/215/225/346/265/213/350/257/225.py" +0 -0
- {cfquant-0.2.36 → cfquant-0.2.38}/cfquant/tests/6_/345/233/236/350/260/203/346/265/213/350/257/225.py" +0 -0
- {cfquant-0.2.36 → cfquant-0.2.38}/cfquant/tests/7_/345/220/214/346/255/245/345/274/202/346/255/245/344/270/213/345/215/225/346/265/213/350/257/225.py" +0 -0
- {cfquant-0.2.36 → cfquant-0.2.38}/cfquant/tests/8_/346/210/220/344/272/244/350/256/242/345/215/225/345/222/214/345/247/224/346/211/230/350/256/242/345/215/225/346/237/245/350/257/242/346/265/213/350/257/225.py" +0 -0
- {cfquant-0.2.36 → cfquant-0.2.38}/cfquant/tests/9_/345/217/257/346/222/244/350/256/242/345/215/225/346/265/213/350/257/225.py" +0 -0
- {cfquant-0.2.36 → cfquant-0.2.38}/cfquant/tests/_helpers.py +0 -0
- {cfquant-0.2.36 → cfquant-0.2.38}/cfquant/tests/log/cftrader/346/250/241/346/213/237/350/264/246/345/217/267/346/211/271/351/207/217/344/270/213/345/215/225/346/265/213/350/257/225_20260911_024617.md" +0 -0
- {cfquant-0.2.36 → cfquant-0.2.38}/cfquant/tests/log/cftrader/346/250/241/346/213/237/350/264/246/345/217/267/346/211/271/351/207/217/344/270/213/345/215/225/346/265/213/350/257/225_20260921_175732.md" +0 -0
- {cfquant-0.2.36 → cfquant-0.2.38}/cfquant/tests/readme.md +0 -0
- {cfquant-0.2.36 → cfquant-0.2.38}/cfquant/tests/test_api_tester_browser.py +0 -0
- {cfquant-0.2.36 → cfquant-0.2.38}/cfquant/tests/test_api_tester_web.py +0 -0
- {cfquant-0.2.36 → cfquant-0.2.38}/cfquant/tests/test_binding_delete_confirmation.py +0 -0
- {cfquant-0.2.36 → cfquant-0.2.38}/cfquant/tests/test_cftrader.py +0 -0
- {cfquant-0.2.36 → cfquant-0.2.38}/cfquant/tests/test_cftrader_tutorial.py +0 -0
- {cfquant-0.2.36 → cfquant-0.2.38}/cfquant/tests/test_cftrader_web.py +0 -0
- {cfquant-0.2.36 → cfquant-0.2.38}/cfquant/tests/test_credit_compat.py +0 -0
- {cfquant-0.2.36 → cfquant-0.2.38}/cfquant/tests/test_json_serialization.py +0 -0
- {cfquant-0.2.36 → cfquant-0.2.38}/cfquant/tests/test_log_management.py +0 -0
- {cfquant-0.2.36 → cfquant-0.2.38}/cfquant/tests/test_management_batch.py +0 -0
- {cfquant-0.2.36 → cfquant-0.2.38}/cfquant/tests/test_project_updater.py +0 -0
- {cfquant-0.2.36 → cfquant-0.2.38}/cfquant/tests/test_python_api_reference.py +0 -0
- {cfquant-0.2.36 → cfquant-0.2.38}/cfquant/tests/test_qmt_strategy_browser.py +0 -0
- {cfquant-0.2.36 → cfquant-0.2.38}/cfquant/tests/test_qmt_strategy_web.py +0 -0
- {cfquant-0.2.36 → cfquant-0.2.38}/cfquant/tests/test_tutorial_reader.py +0 -0
- {cfquant-0.2.36 → cfquant-0.2.38}/cfquant/tests/test_tx_auto_import.py +0 -0
- {cfquant-0.2.36 → cfquant-0.2.38}/cfquant/tx.py +0 -0
- {cfquant-0.2.36 → cfquant-0.2.38}/cfquant/xtconstant.py +0 -0
- {cfquant-0.2.36 → cfquant-0.2.38}/cfquant/xtdata.py +0 -0
- {cfquant-0.2.36 → cfquant-0.2.38}/cfquant/xttrader.py +0 -0
- {cfquant-0.2.36 → cfquant-0.2.38}/cfquant.egg-info/SOURCES.txt +0 -0
- {cfquant-0.2.36 → cfquant-0.2.38}/cfquant.egg-info/dependency_links.txt +0 -0
- {cfquant-0.2.36 → cfquant-0.2.38}/cfquant.egg-info/entry_points.txt +0 -0
- {cfquant-0.2.36 → cfquant-0.2.38}/cfquant.egg-info/requires.txt +0 -0
- {cfquant-0.2.36 → cfquant-0.2.38}/cfquant.egg-info/top_level.txt +0 -0
- {cfquant-0.2.36 → cfquant-0.2.38}/cfquant_pipe_hub.py +0 -0
- {cfquant-0.2.36 → cfquant-0.2.38}/cfquant_web_server.py +0 -0
- {cfquant-0.2.36 → cfquant-0.2.38}/qmt_scripts/CFQUANT.py +0 -0
- {cfquant-0.2.36 → cfquant-0.2.38}/qmt_scripts/CFQUANT_CTYPE_ALL_LOWLAT.py +0 -0
- {cfquant-0.2.36 → cfquant-0.2.38}/qmt_scripts/CFQUANT_LITE.py +0 -0
- {cfquant-0.2.36 → cfquant-0.2.38}/qmt_scripts/CFQUANT_TRADE_LOWLAT.py +0 -0
- {cfquant-0.2.36 → cfquant-0.2.38}/qmt_scripts/__init__.py +0 -0
- {cfquant-0.2.36 → cfquant-0.2.38}/qmt_scripts//345/220/214/350/264/246/345/217/267/347/213/254/347/253/213/345/270/202/345/234/272/CFQUANT_CTYPE_ALL_LOWLAT_SH.py" +0 -0
- {cfquant-0.2.36 → cfquant-0.2.38}/qmt_scripts//345/220/214/350/264/246/345/217/267/347/213/254/347/253/213/345/270/202/345/234/272/CFQUANT_CTYPE_ALL_LOWLAT_SZ.py" +0 -0
- {cfquant-0.2.36 → cfquant-0.2.38}/qmt_scripts//345/220/214/350/264/246/345/217/267/347/213/254/347/253/213/345/270/202/345/234/272/CFQUANT_LITE_SH.py" +0 -0
- {cfquant-0.2.36 → cfquant-0.2.38}/qmt_scripts//345/220/214/350/264/246/345/217/267/347/213/254/347/253/213/345/270/202/345/234/272/CFQUANT_LITE_SZ.py" +0 -0
- {cfquant-0.2.36 → cfquant-0.2.38}/qmt_scripts//345/220/214/350/264/246/345/217/267/347/213/254/347/253/213/345/270/202/345/234/272/CFQUANT_TRADE_LOWLAT_SH.py" +0 -0
- {cfquant-0.2.36 → cfquant-0.2.38}/qmt_scripts//345/220/214/350/264/246/345/217/267/347/213/254/347/253/213/345/270/202/345/234/272/CFQUANT_TRADE_LOWLAT_SZ.py" +0 -0
- {cfquant-0.2.36 → cfquant-0.2.38}/qmt_scripts//345/220/214/350/264/246/345/217/267/347/213/254/347/253/213/345/270/202/345/234/272/readme.md" +0 -0
- {cfquant-0.2.36 → cfquant-0.2.38}/requirements.txt +0 -0
- {cfquant-0.2.36 → cfquant-0.2.38}/setup.cfg +0 -0
- {cfquant-0.2.36 → cfquant-0.2.38}/web_dashboard/__init__.py +0 -0
- {cfquant-0.2.36 → cfquant-0.2.38}/web_dashboard/api-tester.js +0 -0
- {cfquant-0.2.36 → cfquant-0.2.38}/web_dashboard/avatars/amber-pulse.svg +0 -0
- {cfquant-0.2.36 → cfquant-0.2.38}/web_dashboard/avatars/copper-grid.svg +0 -0
- {cfquant-0.2.36 → cfquant-0.2.38}/web_dashboard/avatars/market-blue.svg +0 -0
- {cfquant-0.2.36 → cfquant-0.2.38}/web_dashboard/avatars/rose-circuit.svg +0 -0
- {cfquant-0.2.36 → cfquant-0.2.38}/web_dashboard/avatars/signal-green.svg +0 -0
- {cfquant-0.2.36 → cfquant-0.2.38}/web_dashboard/avatars/slate-wave.svg +0 -0
- {cfquant-0.2.36 → cfquant-0.2.38}/web_dashboard/avatars/teal-orbit.svg +0 -0
- {cfquant-0.2.36 → cfquant-0.2.38}/web_dashboard/avatars/violet-node.svg +0 -0
- {cfquant-0.2.36 → cfquant-0.2.38}/web_dashboard/cftrader-api-data.js +0 -0
- {cfquant-0.2.36 → cfquant-0.2.38}/web_dashboard/favicon.svg +0 -0
- {cfquant-0.2.36 → cfquant-0.2.38}/web_dashboard/image/qmt_deploy/image-10.png +0 -0
- {cfquant-0.2.36 → cfquant-0.2.38}/web_dashboard/image/qmt_deploy/image-11.png +0 -0
- {cfquant-0.2.36 → cfquant-0.2.38}/web_dashboard/image/qmt_deploy/image-12.png +0 -0
- {cfquant-0.2.36 → cfquant-0.2.38}/web_dashboard/image/qmt_deploy/image-13.png +0 -0
- {cfquant-0.2.36 → cfquant-0.2.38}/web_dashboard/image/qmt_deploy/image-14.png +0 -0
- {cfquant-0.2.36 → cfquant-0.2.38}/web_dashboard/image/qmt_deploy/image-15.png +0 -0
- {cfquant-0.2.36 → cfquant-0.2.38}/web_dashboard/image/qmt_deploy/image-16.png +0 -0
- {cfquant-0.2.36 → cfquant-0.2.38}/web_dashboard/image/qmt_deploy/image-17.png +0 -0
- {cfquant-0.2.36 → cfquant-0.2.38}/web_dashboard/image/qmt_deploy/image-18.png +0 -0
- {cfquant-0.2.36 → cfquant-0.2.38}/web_dashboard/image/qmt_deploy/image-19.png +0 -0
- {cfquant-0.2.36 → cfquant-0.2.38}/web_dashboard/image/qmt_deploy/image-20.png +0 -0
- {cfquant-0.2.36 → cfquant-0.2.38}/web_dashboard/image/qmt_deploy/image-21.png +0 -0
- {cfquant-0.2.36 → cfquant-0.2.38}/web_dashboard/image/qmt_deploy/image-4.png +0 -0
- {cfquant-0.2.36 → cfquant-0.2.38}/web_dashboard/image/qmt_deploy/image-5.png +0 -0
- {cfquant-0.2.36 → cfquant-0.2.38}/web_dashboard/image/qmt_deploy/image-6.png +0 -0
- {cfquant-0.2.36 → cfquant-0.2.38}/web_dashboard/image/qmt_deploy/image-7.png +0 -0
- {cfquant-0.2.36 → cfquant-0.2.38}/web_dashboard/image/qmt_deploy/image-8.png +0 -0
- {cfquant-0.2.36 → cfquant-0.2.38}/web_dashboard/image/qmt_deploy/image-9.png +0 -0
- {cfquant-0.2.36 → cfquant-0.2.38}/web_dashboard/python-api-data.js +0 -0
- {cfquant-0.2.36 → cfquant-0.2.38}/web_dashboard/python-api.js +0 -0
- {cfquant-0.2.36 → cfquant-0.2.38}/web_dashboard/styles.css +0 -0
- {cfquant-0.2.36 → cfquant-0.2.38}/web_dashboard/vendor/mermaid.min.js +0 -0
|
@@ -1109,7 +1109,8 @@ class CfquantQmtBridge(object):
|
|
|
1109
1109
|
"order_sysid": self._get_value(obj, "m_strOrderSysID"),
|
|
1110
1110
|
"order_type": self._stock_order_type(obj),
|
|
1111
1111
|
"order_time": self._first_value(obj, (
|
|
1112
|
-
"
|
|
1112
|
+
"time",
|
|
1113
|
+
"order_time",
|
|
1113
1114
|
"entrust_time",
|
|
1114
1115
|
"insert_time",
|
|
1115
1116
|
"m_strOrderTime",
|
|
@@ -1197,6 +1198,7 @@ class CfquantQmtBridge(object):
|
|
|
1197
1198
|
"order_sysid": self._get_value(obj, "m_strOrderSysID"),
|
|
1198
1199
|
"traded_id": self._first_value(obj, ("m_strTradeID", "m_strDealID", "m_nTradeID", "m_nDealID")),
|
|
1199
1200
|
"trade_time": self._first_value(obj, (
|
|
1201
|
+
"time",
|
|
1200
1202
|
"trade_time",
|
|
1201
1203
|
"deal_time",
|
|
1202
1204
|
"m_strTradeTime",
|
|
@@ -188,17 +188,15 @@ def _model_items(document):
|
|
|
188
188
|
return section, list(section.getElementsByTagName("item"))
|
|
189
189
|
|
|
190
190
|
|
|
191
|
-
def _strategy_slot_name(account_id, role="normal"):
|
|
192
|
-
"""Return a deterministic name
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
""
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
suffix = "_%s" % market if market in ("SH", "SZ") else ""
|
|
201
|
-
return ("CFQ_%s%s" % (account, suffix))[:64]
|
|
191
|
+
def _strategy_slot_name(account_id, mode="ctypes", role="normal"):
|
|
192
|
+
"""Return a deterministic, mode-specific name in cfquant's namespace."""
|
|
193
|
+
account = re.sub(r"[^A-Z0-9]+", "_", str(account_id or "").upper()).strip("_") or "ACCOUNT"
|
|
194
|
+
if len(account) > 20:
|
|
195
|
+
account = account[-5:]
|
|
196
|
+
mode = normalize_strategy_mode(mode).upper()
|
|
197
|
+
market = str(role or "normal").upper()
|
|
198
|
+
suffix = "_%s" % market if market in ("SH", "SZ") else ""
|
|
199
|
+
return ("CFQ_%s_%s%s" % (account, mode, suffix))[:64]
|
|
202
200
|
|
|
203
201
|
|
|
204
202
|
def _is_managed_strategy_name(name):
|
|
@@ -533,7 +531,7 @@ class QmtStrategyManager:
|
|
|
533
531
|
for role in group["roles"]:
|
|
534
532
|
old_role = previous_roles.get(role["role"])
|
|
535
533
|
old_name = old_role.get("name") if isinstance(old_role, dict) else ""
|
|
536
|
-
expected_name = _strategy_slot_name(row["account_id"], role["role"])
|
|
534
|
+
expected_name = _strategy_slot_name(row["account_id"], mode, role["role"])
|
|
537
535
|
if old_name == expected_name:
|
|
538
536
|
role_names[role["role"]] = old_name
|
|
539
537
|
else:
|
|
@@ -14,6 +14,7 @@ from cfquant.qmt_strategy_deploy import (
|
|
|
14
14
|
QmtStrategyManager, _account_binding, _atomic_write, _read_document,
|
|
15
15
|
_write_json, _resolve_account_binding, account_qmt_roots, managed_source, normalize_strategy_settings,
|
|
16
16
|
normalize_strategy_mode,
|
|
17
|
+
_strategy_slot_name,
|
|
17
18
|
)
|
|
18
19
|
from cfquant.qmt_strategy_package import _cipher, build_package
|
|
19
20
|
from cfquant.qmt_strategy_runtime import _CqStrategyLease
|
|
@@ -29,6 +30,11 @@ def test_strategy_mode_aliases_are_canonical(value, expected):
|
|
|
29
30
|
assert normalize_strategy_mode(value) == expected
|
|
30
31
|
|
|
31
32
|
|
|
33
|
+
def test_strategy_name_contains_mode_and_shortens_long_account():
|
|
34
|
+
name = _strategy_slot_name("ACCOUNT-12345678901234567890", "lite")
|
|
35
|
+
assert name == "CFQ_67890_LITE"
|
|
36
|
+
|
|
37
|
+
|
|
32
38
|
@pytest.fixture
|
|
33
39
|
def deployment(tmp_path):
|
|
34
40
|
root = tmp_path / "QMT"
|
|
@@ -261,7 +267,9 @@ def test_switch_and_delete_revoke_old_generation_and_disable_its_model(deploymen
|
|
|
261
267
|
manager.configure(row, infos)
|
|
262
268
|
new = next(iter(manager.jobs.values()))
|
|
263
269
|
assert old["generation"] != new["generation"]
|
|
264
|
-
assert old["roles"][0]["name"]
|
|
270
|
+
assert old["roles"][0]["name"] != new["roles"][0]["name"]
|
|
271
|
+
assert old["roles"][0]["name"].endswith("_CTYPES")
|
|
272
|
+
assert new["roles"][0]["name"].endswith("_LITE")
|
|
265
273
|
assert json.loads(Path(old["control_path"]).read_text())["mode"] == "lite"
|
|
266
274
|
running[0] = False
|
|
267
275
|
manager.process_once()
|
|
@@ -289,7 +297,7 @@ def test_historical_generated_name_is_disabled_for_the_same_account(deployment):
|
|
|
289
297
|
manager.configure(row, infos)
|
|
290
298
|
manager.process_once()
|
|
291
299
|
assert models(root)["CFQ_CTYPES_DEADBEEF_NORMAL"].getAttribute("startupAutorun") == "0"
|
|
292
|
-
assert next(iter(manager.jobs.values()))["roles"][0]["name"] == "CFQ_%
|
|
300
|
+
assert next(iter(manager.jobs.values()))["roles"][0]["name"] == "CFQ_%s_CTYPES" % ACCOUNT
|
|
293
301
|
|
|
294
302
|
|
|
295
303
|
def test_independent_identity_for_two_accounts_in_one_qmt(deployment):
|
|
@@ -501,7 +509,7 @@ def test_market_routes_only_import_market_entries_and_use_their_own_stock(deploy
|
|
|
501
509
|
for role in job["roles"]:
|
|
502
510
|
model = models(root)[role["name"]]
|
|
503
511
|
assert model.getAttribute("stock") == {"SH": "SH000300", "SZ": "SZ399001"}[role["role"]]
|
|
504
|
-
assert {role["name"] for role in job["roles"]} == {"CFQ_%
|
|
512
|
+
assert {role["name"] for role in job["roles"]} == {"CFQ_%s_CTYPES_SH" % ACCOUNT, "CFQ_%s_CTYPES_SZ" % ACCOUNT}
|
|
505
513
|
|
|
506
514
|
|
|
507
515
|
def descriptor(tmp_path, generation, role="normal"):
|
|
@@ -3067,7 +3067,8 @@ class TxTradeBridge(object):
|
|
|
3067
3067
|
"order_sysid": self._get_value(obj, "m_strOrderSysID"),
|
|
3068
3068
|
"order_type": self._stock_order_type(obj),
|
|
3069
3069
|
"order_time": self._first_value(obj, (
|
|
3070
|
-
"
|
|
3070
|
+
"time",
|
|
3071
|
+
"order_time",
|
|
3071
3072
|
"entrust_time",
|
|
3072
3073
|
"insert_time",
|
|
3073
3074
|
"m_strOrderTime",
|
|
@@ -3163,7 +3164,8 @@ class TxTradeBridge(object):
|
|
|
3163
3164
|
"contract_no": self._first_value(obj, ("contract_no", "m_strCompactNo", "m_strContractNo", "m_strCompactID")),
|
|
3164
3165
|
"stock_code1": self._first_value(obj, ("stock_code1", "m_stockCode", "m_strStockCode1", "m_strUnderCode")),
|
|
3165
3166
|
"trade_time": self._first_value(obj, (
|
|
3166
|
-
"
|
|
3167
|
+
"time",
|
|
3168
|
+
"trade_time",
|
|
3167
3169
|
"deal_time",
|
|
3168
3170
|
"m_strTradeTime",
|
|
3169
3171
|
"m_strDealTime",
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
# -*- coding: utf-8 -*-
|
|
2
|
+
import datetime
|
|
2
3
|
import re
|
|
3
4
|
|
|
4
5
|
from . import xtconstant
|
|
@@ -198,31 +199,62 @@ def _coerce_bool(value, default=False):
|
|
|
198
199
|
return default
|
|
199
200
|
|
|
200
201
|
|
|
201
|
-
def
|
|
202
|
-
"""Convert QMT's
|
|
202
|
+
def _coerce_timestamp(value, date_value=None, default=0):
|
|
203
|
+
"""Convert QMT's display time to MiniQMT's Unix timestamp in seconds."""
|
|
203
204
|
if value is None or isinstance(value, bool):
|
|
204
205
|
return default
|
|
205
206
|
if isinstance(value, int):
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
207
|
+
if value >= 100000000000:
|
|
208
|
+
return value // 1000
|
|
209
|
+
if value >= 100000000:
|
|
210
|
+
return value
|
|
211
|
+
text = str(value)
|
|
212
|
+
elif isinstance(value, float):
|
|
213
|
+
if value >= 100000000000:
|
|
214
|
+
return int(value / 1000)
|
|
215
|
+
if value >= 100000000:
|
|
216
|
+
return int(value)
|
|
217
|
+
text = str(int(value)) if value.is_integer() else str(value)
|
|
218
|
+
else:
|
|
219
|
+
text = str(value).strip()
|
|
210
220
|
if not text:
|
|
211
221
|
return default
|
|
212
|
-
if re.fullmatch(r"[+-]?\d
|
|
222
|
+
if re.fullmatch(r"[+-]?\d{9,}", text):
|
|
213
223
|
try:
|
|
214
|
-
|
|
224
|
+
number = int(text)
|
|
225
|
+
return number // 1000 if number >= 100000000000 else number
|
|
215
226
|
except ValueError:
|
|
216
227
|
return default
|
|
217
228
|
digits = re.sub(r"\D", "", text)
|
|
218
229
|
if not digits:
|
|
219
230
|
return default
|
|
231
|
+
# HHMMSS / HHMMSSmmm values need the trading date before they can
|
|
232
|
+
# represent the same Unix timestamp exposed by native xtquant.
|
|
233
|
+
if len(digits) not in (5, 6, 8, 9):
|
|
234
|
+
return default
|
|
235
|
+
if len(digits) == 5:
|
|
236
|
+
digits = "0" + digits
|
|
237
|
+
hour, minute, second = int(digits[:2]), int(digits[2:4]), int(digits[4:6])
|
|
238
|
+
microsecond = int((digits[6:] + "000000")[:6]) if len(digits) > 6 else 0
|
|
239
|
+
date_text = re.sub(r"\D", "", str(date_value or ""))
|
|
240
|
+
if len(date_text) != 8:
|
|
241
|
+
return default
|
|
220
242
|
try:
|
|
221
|
-
|
|
222
|
-
|
|
243
|
+
dt = datetime.datetime.strptime(date_text, "%Y%m%d").replace(
|
|
244
|
+
hour=hour, minute=minute, second=second, microsecond=microsecond,
|
|
245
|
+
tzinfo=datetime.timezone(datetime.timedelta(hours=8)),
|
|
246
|
+
)
|
|
247
|
+
return int(dt.timestamp())
|
|
248
|
+
except (TypeError, ValueError, OverflowError):
|
|
223
249
|
return default
|
|
224
250
|
|
|
225
251
|
|
|
252
|
+
def _time_field_timestamp(data, time_names, date_names):
|
|
253
|
+
value = _first_value(data, time_names, default=None)
|
|
254
|
+
date_value = _first_value(data, date_names, default=None)
|
|
255
|
+
return _coerce_timestamp(value, date_value)
|
|
256
|
+
|
|
257
|
+
|
|
226
258
|
def normalize_order_price_type(value, market=""):
|
|
227
259
|
"""Translate documented QMT broker price enums, preserving unknown values."""
|
|
228
260
|
try:
|
|
@@ -525,8 +557,9 @@ class XtOrder(DictObject):
|
|
|
525
557
|
"sysid",
|
|
526
558
|
"m_strOrderID",
|
|
527
559
|
), default="")
|
|
528
|
-
_set_first(data, "order_time", (
|
|
529
|
-
"
|
|
560
|
+
_set_first(data, "order_time", (
|
|
561
|
+
"time",
|
|
562
|
+
"entrust_time",
|
|
530
563
|
"insert_time",
|
|
531
564
|
"m_strOrderTime",
|
|
532
565
|
"m_strEntrustTime",
|
|
@@ -600,7 +633,11 @@ class XtOrder(DictObject):
|
|
|
600
633
|
data["stock_code"] = _coerce_text(data.get("stock_code"))
|
|
601
634
|
data["order_id"] = _coerce_int(data.get("order_id"), -1)
|
|
602
635
|
data["order_sysid"] = _coerce_text(data.get("order_sysid"))
|
|
603
|
-
data["order_time"] =
|
|
636
|
+
data["order_time"] = _time_field_timestamp(
|
|
637
|
+
data,
|
|
638
|
+
("order_time", "time", "entrust_time", "insert_time", "m_strOrderTime", "m_strEntrustTime", "m_strInsertTime", "m_nOrderTime", "m_nEntrustTime", "m_nInsertTime"),
|
|
639
|
+
("order_date", "entrust_date", "m_strOrderDate", "m_strEntrustDate", "m_strTradingDay", "m_nOrderDate", "m_nEntrustDate"),
|
|
640
|
+
)
|
|
604
641
|
for name in ("order_type", "order_volume", "price_type", "traded_volume", "order_status", "direction", "offset_flag"):
|
|
605
642
|
data[name] = _coerce_int(data.get(name))
|
|
606
643
|
for name in ("price", "traded_price"):
|
|
@@ -636,7 +673,7 @@ class XtCreditOrder(XtOrder):
|
|
|
636
673
|
account_id=_coerce_text(data.get("account_id")),
|
|
637
674
|
stock_code=_coerce_text(data.get("stock_code")),
|
|
638
675
|
order_id=_coerce_int(data.get("order_id"), -1),
|
|
639
|
-
order_time=
|
|
676
|
+
order_time=data.get("order_time", 0),
|
|
640
677
|
order_type=_coerce_int(data.get("order_type")),
|
|
641
678
|
order_volume=_coerce_int(data.get("order_volume")),
|
|
642
679
|
price_type=_coerce_int(data.get("price_type")),
|
|
@@ -698,8 +735,9 @@ class XtTrade(DictObject):
|
|
|
698
735
|
"m_nTradeID",
|
|
699
736
|
"m_nDealID",
|
|
700
737
|
), default="")
|
|
701
|
-
_set_first(data, "traded_time", (
|
|
702
|
-
"
|
|
738
|
+
_set_first(data, "traded_time", (
|
|
739
|
+
"time",
|
|
740
|
+
"trade_time",
|
|
703
741
|
"deal_time",
|
|
704
742
|
"m_strTradeTime",
|
|
705
743
|
"m_strDealTime",
|
|
@@ -763,7 +801,11 @@ class XtTrade(DictObject):
|
|
|
763
801
|
data["stock_code"] = _coerce_text(data.get("stock_code"))
|
|
764
802
|
data["order_type"] = _coerce_int(data.get("order_type"))
|
|
765
803
|
data["traded_id"] = _coerce_text(data.get("traded_id"))
|
|
766
|
-
data["traded_time"] =
|
|
804
|
+
data["traded_time"] = _time_field_timestamp(
|
|
805
|
+
data,
|
|
806
|
+
("traded_time", "time", "trade_time", "deal_time", "m_strTradeTime", "m_strDealTime", "m_nTradeTime", "m_nDealTime"),
|
|
807
|
+
("trade_date", "deal_date", "m_strTradeDate", "m_strDealDate", "m_strTradingDay", "m_nTradeDate", "m_nDealDate"),
|
|
808
|
+
)
|
|
767
809
|
for name in ("traded_volume",):
|
|
768
810
|
data[name] = _coerce_int(data.get(name))
|
|
769
811
|
for name in ("traded_price", "traded_amount", "commission"):
|
|
@@ -803,7 +845,7 @@ class XtCreditDeal(DictObject):
|
|
|
803
845
|
account_id=_coerce_text(data.get("account_id")),
|
|
804
846
|
stock_code=_coerce_text(data.get("stock_code")),
|
|
805
847
|
traded_id=_coerce_text(data.get("traded_id")),
|
|
806
|
-
traded_time=
|
|
848
|
+
traded_time=data.get("traded_time", 0),
|
|
807
849
|
traded_price=_coerce_float(data.get("traded_price")),
|
|
808
850
|
traded_volume=_coerce_int(data.get("traded_volume")),
|
|
809
851
|
order_id=_coerce_int(data.get("order_id"), -1),
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const FRONTEND_VERSION = '
|
|
1
|
+
const FRONTEND_VERSION = 'web_20260923_02';
|
|
2
2
|
|
|
3
3
|
const state = {
|
|
4
4
|
accountId: '',
|
|
@@ -2500,9 +2500,42 @@ function normalizeApiBaseUrl(value) {
|
|
|
2500
2500
|
}
|
|
2501
2501
|
}
|
|
2502
2502
|
|
|
2503
|
+
function isPrivateApiHost(host) {
|
|
2504
|
+
host = String(host || '').trim().toLowerCase();
|
|
2505
|
+
if (!host || host === 'localhost' || host === '::1' || host === '[::1]') return true;
|
|
2506
|
+
if (/^127\./.test(host)) return true;
|
|
2507
|
+
const parts = host.split('.').map((item) => Number(item));
|
|
2508
|
+
if (parts.length !== 4 || parts.some((item) => !Number.isInteger(item) || item < 0 || item > 255)) return false;
|
|
2509
|
+
return parts[0] === 10
|
|
2510
|
+
|| parts[0] === 192 && parts[1] === 168
|
|
2511
|
+
|| parts[0] === 172 && parts[1] >= 16 && parts[1] <= 31
|
|
2512
|
+
|| parts[0] === 169 && parts[1] === 254;
|
|
2513
|
+
}
|
|
2514
|
+
|
|
2515
|
+
function apiBaseUrlForPage(value) {
|
|
2516
|
+
const configured = normalizeApiBaseUrl(value);
|
|
2517
|
+
const page = normalizeApiBaseUrl(window.location.origin);
|
|
2518
|
+
try {
|
|
2519
|
+
const configuredUrl = new URL(configured);
|
|
2520
|
+
const pageUrl = new URL(page);
|
|
2521
|
+
// A saved LAN address belongs to the machine that last ran Web. When the
|
|
2522
|
+
// page is opened from another private/loopback address, follow the current
|
|
2523
|
+
// page so changing the host IP does not leave the tester pointing at the
|
|
2524
|
+
// old machine. Public/explicit remote URLs remain user-configurable.
|
|
2525
|
+
if (isPrivateApiHost(configuredUrl.hostname)
|
|
2526
|
+
&& isPrivateApiHost(pageUrl.hostname)
|
|
2527
|
+
&& configuredUrl.hostname !== pageUrl.hostname) {
|
|
2528
|
+
return page;
|
|
2529
|
+
}
|
|
2530
|
+
} catch (error) {
|
|
2531
|
+
return page;
|
|
2532
|
+
}
|
|
2533
|
+
return configured;
|
|
2534
|
+
}
|
|
2535
|
+
|
|
2503
2536
|
function currentApiBaseUrl() {
|
|
2504
2537
|
const input = $('apiBaseUrlInput');
|
|
2505
|
-
if (input && input.value.trim()) return
|
|
2538
|
+
if (input && input.value.trim()) return apiBaseUrlForPage(input.value);
|
|
2506
2539
|
return normalizeApiBaseUrl(window.location.origin);
|
|
2507
2540
|
}
|
|
2508
2541
|
|
|
@@ -4616,7 +4649,10 @@ function renderServerAccessLegacy(info) {
|
|
|
4616
4649
|
|
|
4617
4650
|
const baseInput = $('apiBaseUrlInput');
|
|
4618
4651
|
if (baseInput && !baseInput.value.trim()) {
|
|
4619
|
-
baseInput.value =
|
|
4652
|
+
baseInput.value = apiBaseUrlForPage(state.serverAccess.api_base_url || window.location.origin);
|
|
4653
|
+
} else if (baseInput && baseInput.value.trim()) {
|
|
4654
|
+
const effectiveBaseUrl = apiBaseUrlForPage(baseInput.value);
|
|
4655
|
+
if (effectiveBaseUrl !== normalizeApiBaseUrl(baseInput.value)) baseInput.value = effectiveBaseUrl;
|
|
4620
4656
|
}
|
|
4621
4657
|
updateApiRequestPreview();
|
|
4622
4658
|
}
|
|
@@ -4732,7 +4768,10 @@ function renderServerAccess(info) {
|
|
|
4732
4768
|
const baseInput = $('apiBaseUrlInput');
|
|
4733
4769
|
if (baseInput && !baseInput.value.trim()) {
|
|
4734
4770
|
const currentUrl = state.serverAccess.api_base_url || state.serverAccess.local_url || window.location.origin;
|
|
4735
|
-
baseInput.value =
|
|
4771
|
+
baseInput.value = apiBaseUrlForPage(currentUrl);
|
|
4772
|
+
} else if (baseInput && baseInput.value.trim()) {
|
|
4773
|
+
const effectiveBaseUrl = apiBaseUrlForPage(baseInput.value);
|
|
4774
|
+
if (effectiveBaseUrl !== normalizeApiBaseUrl(baseInput.value)) baseInput.value = effectiveBaseUrl;
|
|
4736
4775
|
}
|
|
4737
4776
|
if (!authEnabled) {
|
|
4738
4777
|
clearWebAuthToken();
|
|
@@ -10369,7 +10408,7 @@ async function loadConfigLegacy() {
|
|
|
10369
10408
|
const savedBaseUrl = data.server_access && data.server_access.api_base_url
|
|
10370
10409
|
? data.server_access.api_base_url
|
|
10371
10410
|
: window.location.origin;
|
|
10372
|
-
apiBaseInput.value =
|
|
10411
|
+
apiBaseInput.value = apiBaseUrlForPage(savedBaseUrl);
|
|
10373
10412
|
}
|
|
10374
10413
|
renderServerAccess(data.server_access);
|
|
10375
10414
|
renderUserProfile(data.user_profile);
|
|
@@ -10430,7 +10469,7 @@ async function loadConfig() {
|
|
|
10430
10469
|
const savedBaseUrl = data.server_access && data.server_access.api_base_url
|
|
10431
10470
|
? data.server_access.api_base_url
|
|
10432
10471
|
: window.location.origin;
|
|
10433
|
-
apiBaseInput.value =
|
|
10472
|
+
apiBaseInput.value = apiBaseUrlForPage(savedBaseUrl);
|
|
10434
10473
|
}
|
|
10435
10474
|
renderServerAccess(data.server_access);
|
|
10436
10475
|
renderUserProfile(data.user_profile);
|
|
@@ -14027,4 +14066,3 @@ async function boot() {
|
|
|
14027
14066
|
}
|
|
14028
14067
|
|
|
14029
14068
|
boot().catch((error) => log('启动失败', { error: error.message }));
|
|
14030
|
-
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
6
6
|
<title>cfquant 控制台</title>
|
|
7
7
|
<link rel="icon" type="image/svg+xml" href="/favicon.svg">
|
|
8
|
-
<link rel="stylesheet" href="/styles.css?v=
|
|
8
|
+
<link rel="stylesheet" href="/styles.css?v=web_20260923_02">
|
|
9
9
|
</head>
|
|
10
10
|
<body>
|
|
11
11
|
<div id="webAuthOverlay" class="auth-overlay hidden" aria-live="polite">
|
|
@@ -3202,7 +3202,6 @@ else:
|
|
|
3202
3202
|
<script src="/cftrader-api-data.js?v=20260911_02"></script>
|
|
3203
3203
|
<script src="/api-tester.js?v=20260916_apikey_01"></script>
|
|
3204
3204
|
<script src="/python-api.js?v=20260911_api_test_01"></script>
|
|
3205
|
-
<script src="/app.js?v=
|
|
3205
|
+
<script src="/app.js?v=web_20260923_02"></script>
|
|
3206
3206
|
</body>
|
|
3207
3207
|
</html>
|
|
3208
|
-
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|