├── .gitignore ├── .gitmodules ├── .vs ├── 996Quant │ └── v15 │ │ └── .suo ├── ProjectSettings.json └── slnx.sqlite ├── 996Quant.pyproj ├── 996Quant.sln ├── LICENSE ├── README.md ├── chapter_02 ├── kline_399300_60min_21-01-29_15_00.pickle ├── kline_399300_day_21-01-29_00_00.pickle └── l01_fbprophet_hs300.ipynb ├── chapter_04 ├── l01_kline_60min_download_jqdatasdk.py ├── l02_hs300_60min_download_jqdatasdk.py └── l03_top1700_60min_download_jqdatasdk.py ├── chapter_06 ├── l01_plot_a_kline.py ├── l02_plot_a_kline_with_ma.py ├── l03_plot_a_kline_with_macd.py └── l04_plot_a_kline_with_boll.py ├── chapter_07 └── l04_robust_peak_point.py └── samples └── data └── cache └── kline_399300_60min.pickle /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | ## 4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 5 | 6 | # User-specific files 7 | *.rsuser 8 | *.suo 9 | *.user 10 | *.userosscache 11 | *.sln.docstates 12 | 13 | # User-specific files (MonoDevelop/Xamarin Studio) 14 | *.userprefs 15 | 16 | # Mono auto generated files 17 | mono_crash.* 18 | 19 | # Build results 20 | [Dd]ebug/ 21 | [Dd]ebugPublic/ 22 | [Rr]elease/ 23 | [Rr]eleases/ 24 | x64/ 25 | x86/ 26 | [Ww][Ii][Nn]32/ 27 | [Aa][Rr][Mm]/ 28 | [Aa][Rr][Mm]64/ 29 | bld/ 30 | [Bb]in/ 31 | [Oo]bj/ 32 | [Ll]og/ 33 | [Ll]ogs/ 34 | 35 | # Visual Studio 2015/2017 cache/options directory 36 | .vs/ 37 | # Uncomment if you have tasks that create the project's static files in wwwroot 38 | #wwwroot/ 39 | 40 | # Visual Studio 2017 auto generated files 41 | Generated\ Files/ 42 | 43 | # MSTest test Results 44 | [Tt]est[Rr]esult*/ 45 | [Bb]uild[Ll]og.* 46 | 47 | # NUnit 48 | *.VisualState.xml 49 | TestResult.xml 50 | nunit-*.xml 51 | 52 | # Build Results of an ATL Project 53 | [Dd]ebugPS/ 54 | [Rr]eleasePS/ 55 | dlldata.c 56 | 57 | # Benchmark Results 58 | BenchmarkDotNet.Artifacts/ 59 | 60 | # .NET Core 61 | project.lock.json 62 | project.fragment.lock.json 63 | artifacts/ 64 | 65 | # ASP.NET Scaffolding 66 | ScaffoldingReadMe.txt 67 | 68 | # StyleCop 69 | StyleCopReport.xml 70 | 71 | # Files built by Visual Studio 72 | *_i.c 73 | *_p.c 74 | *_h.h 75 | *.ilk 76 | *.meta 77 | *.obj 78 | *.iobj 79 | *.pch 80 | *.pdb 81 | *.ipdb 82 | *.pgc 83 | *.pgd 84 | *.rsp 85 | *.sbr 86 | *.tlb 87 | *.tli 88 | *.tlh 89 | *.tmp 90 | *.tmp_proj 91 | *_wpftmp.csproj 92 | *.log 93 | *.vspscc 94 | *.vssscc 95 | .builds 96 | *.pidb 97 | *.svclog 98 | *.scc 99 | 100 | # Chutzpah Test files 101 | _Chutzpah* 102 | 103 | # Visual C++ cache files 104 | ipch/ 105 | *.aps 106 | *.ncb 107 | *.opendb 108 | *.opensdf 109 | *.sdf 110 | *.cachefile 111 | *.VC.db 112 | *.VC.VC.opendb 113 | 114 | # Visual Studio profiler 115 | *.psess 116 | *.vsp 117 | *.vspx 118 | *.sap 119 | 120 | # Visual Studio Trace Files 121 | *.e2e 122 | 123 | # TFS 2012 Local Workspace 124 | $tf/ 125 | 126 | # Guidance Automation Toolkit 127 | *.gpState 128 | 129 | # ReSharper is a .NET coding add-in 130 | _ReSharper*/ 131 | *.[Rr]e[Ss]harper 132 | *.DotSettings.user 133 | 134 | # TeamCity is a build add-in 135 | _TeamCity* 136 | 137 | # DotCover is a Code Coverage Tool 138 | *.dotCover 139 | 140 | # AxoCover is a Code Coverage Tool 141 | .axoCover/* 142 | !.axoCover/settings.json 143 | 144 | # Coverlet is a free, cross platform Code Coverage Tool 145 | coverage*.json 146 | coverage*.xml 147 | coverage*.info 148 | 149 | # Visual Studio code coverage results 150 | *.coverage 151 | *.coveragexml 152 | 153 | # NCrunch 154 | _NCrunch_* 155 | .*crunch*.local.xml 156 | nCrunchTemp_* 157 | 158 | # MightyMoose 159 | *.mm.* 160 | AutoTest.Net/ 161 | 162 | # Web workbench (sass) 163 | .sass-cache/ 164 | 165 | # Installshield output folder 166 | [Ee]xpress/ 167 | 168 | # DocProject is a documentation generator add-in 169 | DocProject/buildhelp/ 170 | DocProject/Help/*.HxT 171 | DocProject/Help/*.HxC 172 | DocProject/Help/*.hhc 173 | DocProject/Help/*.hhk 174 | DocProject/Help/*.hhp 175 | DocProject/Help/Html2 176 | DocProject/Help/html 177 | 178 | # Click-Once directory 179 | publish/ 180 | 181 | # Publish Web Output 182 | *.[Pp]ublish.xml 183 | *.azurePubxml 184 | # Note: Comment the next line if you want to checkin your web deploy settings, 185 | # but database connection strings (with potential passwords) will be unencrypted 186 | *.pubxml 187 | *.publishproj 188 | 189 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 190 | # checkin your Azure Web App publish settings, but sensitive information contained 191 | # in these scripts will be unencrypted 192 | PublishScripts/ 193 | 194 | # NuGet Packages 195 | *.nupkg 196 | # NuGet Symbol Packages 197 | *.snupkg 198 | # The packages folder can be ignored because of Package Restore 199 | **/[Pp]ackages/* 200 | # except build/, which is used as an MSBuild target. 201 | !**/[Pp]ackages/build/ 202 | # Uncomment if necessary however generally it will be regenerated when needed 203 | #!**/[Pp]ackages/repositories.config 204 | # NuGet v3's project.json files produces more ignorable files 205 | *.nuget.props 206 | *.nuget.targets 207 | 208 | # Microsoft Azure Build Output 209 | csx/ 210 | *.build.csdef 211 | 212 | # Microsoft Azure Emulator 213 | ecf/ 214 | rcf/ 215 | 216 | # Windows Store app package directories and files 217 | AppPackages/ 218 | BundleArtifacts/ 219 | Package.StoreAssociation.xml 220 | _pkginfo.txt 221 | *.appx 222 | *.appxbundle 223 | *.appxupload 224 | 225 | # Visual Studio cache files 226 | # files ending in .cache can be ignored 227 | *.[Cc]ache 228 | # but keep track of directories ending in .cache 229 | !?*.[Cc]ache/ 230 | 231 | # Others 232 | ClientBin/ 233 | ~$* 234 | *~ 235 | *.dbmdl 236 | *.dbproj.schemaview 237 | *.jfm 238 | *.pfx 239 | *.publishsettings 240 | orleans.codegen.cs 241 | 242 | # Including strong name files can present a security risk 243 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 244 | #*.snk 245 | 246 | # Since there are multiple workflows, uncomment next line to ignore bower_components 247 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 248 | #bower_components/ 249 | 250 | # RIA/Silverlight projects 251 | Generated_Code/ 252 | 253 | # Backup & report files from converting an old project file 254 | # to a newer Visual Studio version. Backup files are not needed, 255 | # because we have git ;-) 256 | _UpgradeReport_Files/ 257 | Backup*/ 258 | UpgradeLog*.XML 259 | UpgradeLog*.htm 260 | ServiceFabricBackup/ 261 | *.rptproj.bak 262 | 263 | # SQL Server files 264 | *.mdf 265 | *.ldf 266 | *.ndf 267 | 268 | # Business Intelligence projects 269 | *.rdl.data 270 | *.bim.layout 271 | *.bim_*.settings 272 | *.rptproj.rsuser 273 | *- [Bb]ackup.rdl 274 | *- [Bb]ackup ([0-9]).rdl 275 | *- [Bb]ackup ([0-9][0-9]).rdl 276 | 277 | # Microsoft Fakes 278 | FakesAssemblies/ 279 | 280 | # GhostDoc plugin setting file 281 | *.GhostDoc.xml 282 | 283 | # Node.js Tools for Visual Studio 284 | .ntvs_analysis.dat 285 | node_modules/ 286 | 287 | # Visual Studio 6 build log 288 | *.plg 289 | 290 | # Visual Studio 6 workspace options file 291 | *.opt 292 | 293 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 294 | *.vbw 295 | 296 | # Visual Studio LightSwitch build output 297 | **/*.HTMLClient/GeneratedArtifacts 298 | **/*.DesktopClient/GeneratedArtifacts 299 | **/*.DesktopClient/ModelManifest.xml 300 | **/*.Server/GeneratedArtifacts 301 | **/*.Server/ModelManifest.xml 302 | _Pvt_Extensions 303 | 304 | # Paket dependency manager 305 | .paket/paket.exe 306 | paket-files/ 307 | 308 | # FAKE - F# Make 309 | .fake/ 310 | 311 | # CodeRush personal settings 312 | .cr/personal 313 | 314 | # Python Tools for Visual Studio (PTVS) 315 | __pycache__/ 316 | *.pyc 317 | 318 | # Cake - Uncomment if you are using it 319 | # tools/** 320 | # !tools/packages.config 321 | 322 | # Tabs Studio 323 | *.tss 324 | 325 | # Telerik's JustMock configuration file 326 | *.jmconfig 327 | 328 | # BizTalk build output 329 | *.btp.cs 330 | *.btm.cs 331 | *.odx.cs 332 | *.xsd.cs 333 | 334 | # OpenCover UI analysis results 335 | OpenCover/ 336 | 337 | # Azure Stream Analytics local run output 338 | ASALocalRun/ 339 | 340 | # MSBuild Binary and Structured Log 341 | *.binlog 342 | 343 | # NVidia Nsight GPU debugger configuration file 344 | *.nvuser 345 | 346 | # MFractors (Xamarin productivity tool) working folder 347 | .mfractor/ 348 | 349 | # Local History for Visual Studio 350 | .localhistory/ 351 | 352 | # BeatPulse healthcheck temp database 353 | healthchecksdb 354 | 355 | # Backup folder for Package Reference Convert tool in Visual Studio 2017 356 | MigrationBackup/ 357 | 358 | # Ionide (cross platform F# VS Code tools) working folder 359 | .ionide/ 360 | 361 | # Fody - auto-generated XML schema 362 | FodyWeavers.xsd 363 | 364 | # Byte-compiled / optimized / DLL files 365 | __pycache__/ 366 | *.py[cod] 367 | *$py.class 368 | 369 | # C extensions 370 | *.so 371 | 372 | # Distribution / packaging 373 | .Python 374 | build/ 375 | develop-eggs/ 376 | dist/ 377 | downloads/ 378 | eggs/ 379 | .eggs/ 380 | lib/ 381 | lib64/ 382 | parts/ 383 | sdist/ 384 | var/ 385 | wheels/ 386 | pip-wheel-metadata/ 387 | share/python-wheels/ 388 | *.egg-info/ 389 | .installed.cfg 390 | *.egg 391 | MANIFEST 392 | 393 | # PyInstaller 394 | # Usually these files are written by a python script from a template 395 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 396 | *.manifest 397 | *.spec 398 | 399 | # Installer logs 400 | pip-log.txt 401 | pip-delete-this-directory.txt 402 | 403 | # Unit test / coverage reports 404 | htmlcov/ 405 | .tox/ 406 | .nox/ 407 | .coverage 408 | .coverage.* 409 | .cache 410 | nosetests.xml 411 | coverage.xml 412 | *.cover 413 | *.py,cover 414 | .hypothesis/ 415 | .pytest_cache/ 416 | cover/ 417 | 418 | # Translations 419 | *.mo 420 | *.pot 421 | 422 | # Django stuff: 423 | *.log 424 | local_settings.py 425 | db.sqlite3 426 | db.sqlite3-journal 427 | 428 | # Flask stuff: 429 | instance/ 430 | .webassets-cache 431 | 432 | # Scrapy stuff: 433 | .scrapy 434 | 435 | # Sphinx documentation 436 | docs/_build/ 437 | 438 | # PyBuilder 439 | .pybuilder/ 440 | target/ 441 | 442 | # Jupyter Notebook 443 | .ipynb_checkpoints 444 | 445 | # IPython 446 | profile_default/ 447 | ipython_config.py 448 | 449 | # pyenv 450 | # For a library or package, you might want to ignore these files since the code is 451 | # intended to run in multiple environments; otherwise, check them in: 452 | # .python-version 453 | 454 | # pipenv 455 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 456 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 457 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 458 | # install all needed dependencies. 459 | #Pipfile.lock 460 | 461 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow 462 | __pypackages__/ 463 | 464 | # Celery stuff 465 | celerybeat-schedule 466 | celerybeat.pid 467 | 468 | # SageMath parsed files 469 | *.sage.py 470 | 471 | # Environments 472 | .env 473 | .venv 474 | env/ 475 | venv/ 476 | ENV/ 477 | env.bak/ 478 | venv.bak/ 479 | 480 | # Spyder project settings 481 | .spyderproject 482 | .spyproject 483 | 484 | # Rope project settings 485 | .ropeproject 486 | 487 | # mkdocs documentation 488 | /site 489 | 490 | # mypy 491 | .mypy_cache/ 492 | .dmypy.json 493 | dmypy.json 494 | 495 | # Pyre type checker 496 | .pyre/ 497 | 498 | # pytype static type analyzer 499 | .pytype/ 500 | 501 | # Cython debug symbols 502 | cython_debug/ 503 | /datastore/kline 504 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "GolemQ"] 2 | path = GolemQ 3 | url = https://github.com/Rgveda/GolemQ 4 | -------------------------------------------------------------------------------- /.vs/996Quant/v15/.suo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rgveda/996Quant/e36a8e1e684d0cd21bcb70657e349a3d65cfd706/.vs/996Quant/v15/.suo -------------------------------------------------------------------------------- /.vs/ProjectSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "CurrentProjectSetting": null 3 | } -------------------------------------------------------------------------------- /.vs/slnx.sqlite: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rgveda/996Quant/e36a8e1e684d0cd21bcb70657e349a3d65cfd706/.vs/slnx.sqlite -------------------------------------------------------------------------------- /996Quant.pyproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Debug 5 | 2.0 6 | {943eaabe-7c89-4eef-9301-ee45947eb8f5} 7 | 8 | chapter_04\l03_top1700_60min_download_jqdatasdk.py 9 | 10 | . 11 | . 12 | {888888a0-9f3d-457c-b088-3a5042f75d52} 13 | Standard Python launcher 14 | Global|PythonCore|3.7 15 | 16 | 17 | 18 | 19 | 10.0 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | Code 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | -------------------------------------------------------------------------------- /996Quant.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.28307.1259 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{888888A0-9F3D-457C-B088-3A5042F75D52}") = "996Quant", "996Quant.pyproj", "{943EAABE-7C89-4EEF-9301-EE45947EB8F5}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Release|Any CPU = Release|Any CPU 12 | EndGlobalSection 13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 14 | {943EAABE-7C89-4EEF-9301-EE45947EB8F5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 15 | {943EAABE-7C89-4EEF-9301-EE45947EB8F5}.Release|Any CPU.ActiveCfg = Release|Any CPU 16 | EndGlobalSection 17 | GlobalSection(SolutionProperties) = preSolution 18 | HideSolutionNode = FALSE 19 | EndGlobalSection 20 | GlobalSection(ExtensibilityGlobals) = postSolution 21 | SolutionGuid = {08006F86-57AF-4DD4-AF58-62E3C0843BC1} 22 | EndGlobalSection 23 | EndGlobal 24 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Azai 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # GolemQ 2 | 3 | A PowerToys based QUANTAXIS 4 | 5 | 这是一个基于 QUANTAXIS 二次开发的量化系统子项目 6 | 7 | 发起这个子项目的原因是我人称BugKing,也没有精力去仔细测试,有些随手PR的代码可能会干扰QUANTAXIS主版本稳定性(是的,1.9.30版本无法获取A股财报的Bug是我PR上去的\>\_<);某些开发了代码功能存在跟天神原始设计不相同的;或者规划路线图跟天神设计理念不同的;或者依赖或者模仿第三方量化平台接口的(我担心有法律之类的风险,所以也不适合PR到QUANTAXIS)。有的功能和代码因为我不是金融科班出身,也不知道现在的前沿趋势,贸然PR到QUANTAXIS,然后又自己发觉功能不妥或者不实用,然后又匆忙在QUANTAXIS中移除。再比如一部分功能代码我设计为cli命令行格式运行,而QA主要设计为Docker发布运行。 8 | 9 | 这导致了一部分代码因为现实需求被我写出来,正在使用,但是跟QA风格并不匹配,而没有办法在Docker的HTML前端中顺利使用,暂时我也没相处好办法和QUANTAXIS 进行 PR 合并。 10 | 11 | 但是又有很多朋友问这些常用的功能使用情况,为了发布我不得不打包代码,索性发布自己的第一个Git项目吧,也算是人生头一回原创 Git仓库了。 12 | 13 | ## 安装: 14 | 15 | 在 QUANTAXIS Docker 中打开 Dashboard 16 | 17 | 选择 qacommunity,打开 cli 控制台,输入 bash 18 | 19 | 输入 git clone https://github.com/Rgveda/GolemQ.git 20 | 21 | cd GolemQ 22 | 23 | python setup.py install 24 | 25 | ## 使用: 26 | 27 | ### 功能包括: 28 | 29 | 来源新浪财经的A股实盘行情 l1快照数据 30 | 31 | 在 repo 根目录下面,输入: 32 | 33 | python -m GolemQ.cli --sub sina_l1 34 | 35 | 只保存部分股票数据,输入: 36 | 37 | python -m GolemQ.cli --sub sina_l1 --codelist "600783、601069、002152、000582、002013、000960、000881 38 | 、000698、600742、600203、601186、601007、600328、600879" 39 | 40 | ### 读取实盘l1数据 41 | 42 | 这里完成的动作包括,读取l1数据,重采样为1min数据,重采样为日线/小时线数据,具体方法为打开 Jupyter,输入 43 | 44 | *from GolemQ.fetch.kline import \(* 45 |     *get_kline_price,* 46 |     *get_kline_price_min,* 47 | *\)* 48 | 49 | *data_day, codename = get_kline_price\("600519", verbose=True\)* 50 | 51 | 为避免出现很多打印信息,可以设置参数 *verbose=False* 52 | 53 | *data_day, codename = get_kline_price_min\("6003444", verbose=False\)* 54 | 55 | ### 已知Bug: 56 | 57 | 上证指数 000001 实盘走势和平安银行混淆。 目前已经修正 ——2020.11.22 58 | 59 | 成交量:Volumne和Amount 计算方式不对。 60 | 61 | 未能正确处理 *000001.XSHG 600519.SH* 这类格式的代码,能返回K线数据,但是不含今日实盘数据 62 | 63 | ### 常见问题 64 | 65 | 无法运行命令 66 | 67 | *PS C:\Users\azai\source\repos\GolemQ> python -m GolemQ.cli --sub sina_l1* 68 | 69 | 提示 70 | 71 | *C:\Users\azai\AppData\Local\Programs\Python\Python37\python.exe: Error 72 | while finding module specification for 'GolemQ.cli' 73 | (ModuleNotFoundError: No module named 'GolemQ')* 74 | 75 | 解决方法输入 cd .. 切换到上一层目录 76 | 77 | *PS C:\Users\azai\source\repos\GolemQ> cd ..* 78 | 79 | *PS C:\Users\azai\source\repos> python -m GolemQ.cli --sub sina_l1* 80 | 81 | Program Last Time 3.762s 82 | 83 | Not Trading time 现在是中国A股收盘时间 2020-10-15 16:28:05.310437 84 | 85 | Not Trading time 现在是中国A股收盘时间 2020-10-15 16:28:07.314858 86 | 87 | Not Trading time 现在是中国A股收盘时间 2020-10-15 16:28:09.323150 88 | 89 | Not Trading time 现在是中国A股收盘时间 2020-10-15 16:28:11.334017 90 | 91 | 92 | ## 例子 93 | 94 | ### 读取实盘行情数据K线 95 | 96 | 在 repo 根目录下面,输入 97 | 98 | *python -m GolemQ.test_cases.fetch_test.realtime* 99 | 100 | ## 模仿优矿DataAPI数据接口 101 | 102 | 挖了坑,未完成,待续 103 | 104 | ## 计划 105 | 106 | 模仿聚宽API接口——To be continue... 107 | 108 | Firstblood! 109 | 110 | By 阿财 111 | 112 | 2020.10.14 -------------------------------------------------------------------------------- /chapter_02/kline_399300_60min_21-01-29_15_00.pickle: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rgveda/996Quant/e36a8e1e684d0cd21bcb70657e349a3d65cfd706/chapter_02/kline_399300_60min_21-01-29_15_00.pickle -------------------------------------------------------------------------------- /chapter_02/kline_399300_day_21-01-29_00_00.pickle: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rgveda/996Quant/e36a8e1e684d0cd21bcb70657e349a3d65cfd706/chapter_02/kline_399300_day_21-01-29_00_00.pickle -------------------------------------------------------------------------------- /chapter_04/l01_kline_60min_download_jqdatasdk.py: -------------------------------------------------------------------------------- 1 | # coding:utf-8 2 | # 3 | # The MIT License (MIT) 4 | # 5 | # Copyright (c) 2018-2020 azai/Rgveda/GolemQuant 6 | # 7 | # Permission is hereby granted, free of charge, to any person obtaining a copy 8 | # of this software and associated documentation files (the "Software"), to deal 9 | # in the Software without restriction, including without limitation the rights 10 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | # copies of the Software, and to permit persons to whom the Software is 12 | # furnished to do so, subject to the following conditions: 13 | # 14 | # The above copyright notice and this permission notice shall be included in 15 | # all 16 | # copies or substantial portions of the Software. 17 | # 18 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 24 | # SOFTWARE. 25 | # 26 | """ 27 | 聚宽小时线(60分钟线)数据下载,范围精选白马蓝筹股,下载到当前目录 \datastore\kline\stock\ 下 28 | 需开通聚宽本地数据接口,文档:https://www.joinquant.com/help/api/help?name=JQData 29 | 申请地址: https://www.joinquant.com/default/index/sdk#jq-sdk-apply 30 | """ 31 | 32 | import os 33 | import datetime 34 | import pandas as pd 35 | import numpy as np 36 | import time 37 | 38 | from jqdatasdk import ( 39 | auth, 40 | is_auth, 41 | get_query_count, 42 | api as jqapi, 43 | ) 44 | from GolemQ.utils.path import ( 45 | mkdirs, 46 | export_metadata_to_pickle, 47 | import_metadata_from_pickle, 48 | ) 49 | from GolemQ.utils.settings import ( 50 | exists_settings, 51 | input_settings, 52 | load_settings, 53 | save_settings, 54 | ) 55 | try: 56 | import QUANTAXIS as QA 57 | except: 58 | print('PLEASE run "pip install QUANTAXIS" to call these modules') 59 | pass 60 | 61 | if __name__ == '__main__': 62 | # 定义保存云端量化数据源用户名密码的的 pd.DataFrame 结构 63 | password = pd.DataFrame({'host':['jqdatasdk'], 64 | 'username':[None], 65 | 'password':[None]}, 66 | columns=['host', 67 | 'username', 68 | 'password']) 69 | 70 | # 将用户密码token等信息保存到系统的当前用户目录 %userprofile%/.GolemQ 目录下面 71 | pwd_save_file = 'jqdatasdk_pwd.pickle' 72 | if (exists_settings(pwd_save_file)): 73 | password = load_settings(pwd_save_file) 74 | else: 75 | password = input_settings(pattern=password, 76 | filename=pwd_save_file,) 77 | save_settings(pwd_save_file, password) 78 | 79 | #ID是申请时所填写的手机号;Password为聚宽官网登录密码,新申请用户默认为手机号后6位 80 | auth(password.username[0], 81 | password.password[0]) 82 | is_auth = is_auth() 83 | 84 | # 查询当日剩余可调用条数 85 | print(get_query_count()) 86 | print(is_auth) 87 | 88 | indexlist = [ '000001.XSHG', '000002.XSHG', '000003.XSHG', '000004.XSHG', 89 | '000005.XSHG', '000006.XSHG', '000007.XSHG', '000009.XSHG', 90 | '000009.XSHG', '000010.XSHG', '000015.XSHG', '000016.XSHG', 91 | '000036.XSHG', '000037.XSHG', '000038.XSHG', '000039.XSHG', 92 | '000040.XSHG', '000300.XSHG', '000112.XSHG', '000133.XSHG', 93 | '000903.XSHG', '000905.XSHG', '000906.XSHG', '000993.XSHG', 94 | '000989.XSHG', '000990.XSHG', '000991.XSHG', '000992.XSHG', 95 | '399001', '399006', 96 | '513030', '399684', '159934', '512000', 97 | '159987', '399616', '510050', '513100', 98 | '510850', '518880', '510180', '159916', 99 | '512980', '512090', '515000', 100 | '510900', '512910', '513050', '510300', 101 | '399384', '510810', '399987', '159905', 102 | '399396', '399997', '159919', 103 | '159941', '159920', ] 104 | indexlist = jqapi.normalize_code(indexlist) 105 | code = indexlist[0] 106 | 107 | # 创建数据下载目录 108 | frequence = '60min' 109 | index_path = mkdirs(os.path.join(mkdirs('datastore'), 110 | 'kline', 'index', frequence)) 111 | print(index_path) 112 | 113 | for year in range(2017, 2005, -1): 114 | start_date = '{}-01-01'.format(year) 115 | end_date = '{}-01-02'.format(year + 1) 116 | for asset in indexlist: 117 | print(asset, start_date, end_date,) 118 | indexfile = os.path.join(index_path, u'{}_{}_{}.pickle'.format(asset, 119 | year, 120 | frequence)) 121 | if os.path.isfile(indexfile ): 122 | print('文件已经存在,跳过 ', indexfile) 123 | continue 124 | try: 125 | print(indexfile ) 126 | his = jqapi.get_price(asset, start_date, end_date, frequency='60m') 127 | export_metadata_to_pickle(index_path, u'{}_{}'.format(asset, year), 128 | metadata=his) 129 | #data_day = QA.QA_fetch_stock_min_adv(codelist, 130 | # start='2019-01-01', 131 | # end='2020-08-28', 132 | # frequence='60min') 133 | #his = data_day.data 134 | except Exception as e: 135 | print(asset, e) 136 | time.sleep(1) 137 | 138 | 139 | for year in range(2017, 2005, -1): 140 | start_date = '{}-01-01'.format(year) 141 | end_date = '{}-01-02'.format(year + 1) 142 | for asset in indexlist: 143 | print(asset, start_date, end_date,) 144 | indexfile = os.path.join(index_path, u'{}_{}_{}.pickle'.format(asset, year, frequence)) 145 | his = import_metadata_from_pickle(index_path, u'{}_{}'.format(asset, year)) 146 | print(his.head(10)) 147 | 148 | 149 | # 创建数据下载目录 150 | frequence = '60min' 151 | stock_path = mkdirs(os.path.join(mkdirs('datastore'), 'kline', 'stock', frequence)) 152 | print(stock_path) 153 | 154 | stocklist = ['002230', '600900', '300560', '300146', 155 | '002271', '603129', '002557', '002603', 156 | '600161', '600477', '000661', '600519', 157 | '603520', '002503', '000157', '002179', 158 | '600585', '600298', '600104', '002594', 159 | '603288', '300760', '300715', '002007', 160 | '002258', '300433', '300059', '600612', 161 | '603515', '603486', '002352', '300314', 162 | '600332', '601138', '600522', '600031', 163 | '600436', '603444', '601933', '601611', 164 | '000876', '002714', '002415', '601558', 165 | '603517', '000895', '603259', '002831', 166 | '000333', '300498', '601100', '600030', 167 | '600188', '600352', '600009', '002382', 168 | '600887', '601888', '600309', '000858', 169 | '002475', '603713', '300750', '002050', 170 | '600547', '600660', '600570', '603899', 171 | '002705', '300015', '601877', '000568', 172 | '600486', '300144', '600276', '000651', 173 | '601318', '600563', '600066', '300122', 174 | '300263', '601857', '600600', '000538', 175 | '300325', '000671', '600036'] 176 | #stocklist = [] 177 | stocklist = jqapi.normalize_code(stocklist) 178 | 179 | for year in range(2017, 2005, -1): 180 | start_date = '{}-01-01'.format(year) 181 | end_date = '{}-01-02'.format(year + 1) 182 | for asset in stocklist: 183 | print(asset, start_date, end_date,) 184 | stockfile = os.path.join(stock_path, u'{}_{}_{}.pickle'.format(asset, year, frequence)) 185 | if os.path.isfile(stockfile ): 186 | print('文件已经存在,跳过 ', stockfile) 187 | continue 188 | try: 189 | print(stockfile ) 190 | his = jqapi.get_price(asset, start_date, end_date, frequency='60m') 191 | export_metadata_to_pickle(stock_path, u'{}_{}'.format(asset, year), metadata=his) 192 | #data_day = QA.QA_fetch_stock_min_adv(codelist, 193 | # start='2019-01-01', 194 | # end='2020-08-28', 195 | # frequence='60min') 196 | #his = data_day.data 197 | except Exception as e: 198 | print(asset, e) 199 | time.sleep(1) 200 | 201 | 202 | for year in range(2017, 2005, -1): 203 | start_date = '{}-01-01'.format(year) 204 | end_date = '{}-01-02'.format(year + 1) 205 | for asset in stocklist: 206 | print(asset, start_date, end_date,) 207 | stockfile = os.path.join(stock_path, u'{}_{}_{}.pickle'.format(asset, year, frequence)) 208 | his = import_metadata_from_pickle(stock_path, u'{}_{}'.format(asset, year)) 209 | print(his.head(10)) -------------------------------------------------------------------------------- /chapter_04/l02_hs300_60min_download_jqdatasdk.py: -------------------------------------------------------------------------------- 1 | # coding:utf-8 2 | # 3 | # The MIT License (MIT) 4 | # 5 | # Copyright (c) 2018-2020 azai/Rgveda/GolemQuant 6 | # 7 | # Permission is hereby granted, free of charge, to any person obtaining a copy 8 | # of this software and associated documentation files (the "Software"), to deal 9 | # in the Software without restriction, including without limitation the rights 10 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | # copies of the Software, and to permit persons to whom the Software is 12 | # furnished to do so, subject to the following conditions: 13 | # 14 | # The above copyright notice and this permission notice shall be included in 15 | # all 16 | # copies or substantial portions of the Software. 17 | # 18 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 24 | # SOFTWARE. 25 | # 26 | """ 27 | 聚宽小时线(60分钟线)数据下载,范围 沪深300,下载到当前目录 \datastore\kline\stock\ 下 28 | 需开通聚宽本地数据接口,文档:https://www.joinquant.com/help/api/help?name=JQData 29 | 申请地址: https://www.joinquant.com/default/index/sdk#jq-sdk-apply 30 | """ 31 | 32 | import os 33 | import datetime 34 | import pandas as pd 35 | import numpy as np 36 | import time 37 | 38 | from jqdatasdk import ( 39 | auth, 40 | is_auth, 41 | get_query_count, 42 | api as jqapi, 43 | ) 44 | from GolemQ.utils.path import ( 45 | mkdirs, 46 | export_metadata_to_pickle, 47 | import_metadata_from_pickle, 48 | ) 49 | from GolemQ.utils.settings import ( 50 | exists_settings, 51 | input_settings, 52 | load_settings, 53 | save_settings, 54 | ) 55 | try: 56 | import QUANTAXIS as QA 57 | except: 58 | print('PLEASE run "pip install QUANTAXIS" to call these modules') 59 | pass 60 | 61 | if __name__ == '__main__': 62 | # 定义保存云端量化数据源用户名密码的的 pd.DataFrame 结构 63 | password = pd.DataFrame({'host':['jqdatasdk'], 64 | 'username':[None], 65 | 'password':[None]}, 66 | columns=['host', 67 | 'username', 68 | 'password']) 69 | 70 | # 将用户密码token等信息保存到系统的当前用户目录 %userprofile%/.GolemQ 目录下面 71 | pwd_save_file = 'jqdatasdk_pwd.pickle' 72 | if (exists_settings(pwd_save_file)): 73 | password = load_settings(pwd_save_file) 74 | else: 75 | password = input_settings(pattern=password, 76 | filename=pwd_save_file,) 77 | save_settings(pwd_save_file, password) 78 | 79 | #ID是申请时所填写的手机号;Password为聚宽官网登录密码,新申请用户默认为手机号后6位 80 | auth(password.username[0], 81 | password.password[0]) 82 | asset = u'000001.XSHE' 83 | is_auth = is_auth() 84 | 85 | # 查询当日剩余可调用条数 86 | print(get_query_count()) 87 | print(is_auth) 88 | 89 | # 创建数据下载目录 90 | frequence = '60min' 91 | stock_path = mkdirs(os.path.join(mkdirs('datastore'), 'kline', 92 | 'stock', frequence)) 93 | print(stock_path) 94 | 95 | for year in range(2017, 2005, -1): 96 | last_query_count = get_query_count() 97 | print(u'剩余可查询条数', last_query_count) 98 | stocklists = [] 99 | for month in range(1, 12): 100 | index_date = '{}-{}-01'.format(year, month) 101 | # 获取特定日期截面的所有沪深300的股票成分 102 | stocklist = jqapi.get_index_stocks('000300.XSHG', 103 | date=index_date) 104 | time.sleep(0.2) 105 | stocklists = stocklists + stocklist 106 | 107 | # 去除重复代码 108 | stocklists = list(set(stocklists)) 109 | print(u'{}年 沪深300指数 一共有成分个股:{}个'.format(year, 110 | len(stocklists)), 111 | stocklists) 112 | stocklists = jqapi.normalize_code(stocklists) 113 | 114 | start_date = '{}-01-01'.format(year) 115 | end_date = '{}-01-02'.format(year + 1) 116 | for asset in stocklists: 117 | if (last_query_count['spare'] < 1280): 118 | print(u'剩余查询条数已经不足,退出行情查询抓取...') 119 | break 120 | 121 | print(asset, start_date, end_date,) 122 | stockfile = os.path.join(stock_path, 123 | u'{}_{}_{}.pickle'.format(asset, 124 | year, 125 | frequence)) 126 | if os.path.isfile(stockfile): 127 | print('文件已经存在,跳过 ', stockfile) 128 | continue 129 | try: 130 | print(stockfile) 131 | his = jqapi.get_price(asset, 132 | start_date, 133 | end_date, 134 | frequency='60m') 135 | export_metadata_to_pickle(stock_path, 136 | u'{}_{}'.format(asset, 137 | year), 138 | metadata=his) 139 | except Exception as e: 140 | last_query_count = get_query_count() 141 | print(asset, last_query_count, e) 142 | time.sleep(1) 143 | 144 | 145 | for year in range(2017, 2005, -1): 146 | stocklists = [] 147 | for month in range(1, 12): 148 | index_date = '{}-{}-01'.format(year, month) 149 | # 获取特定日期截面的所有沪深300的股票成分 150 | stocklist = jqapi.get_index_stocks('000300.XSHG', 151 | date=index_date) 152 | time.sleep(0.2) 153 | stocklists = stocklists + stocklist 154 | 155 | # 去除重复代码 156 | stocklists = list(set(stocklists)) 157 | print(u'查验数据 {}年 沪深300指数 一共有成分个股:{}个'.format(year, 158 | len(stocklists)), 159 | stocklists) 160 | stocklists = jqapi.normalize_code(stocklists) 161 | 162 | start_date = '{}-01-01'.format(year) 163 | end_date = '{}-01-02'.format(year + 1) 164 | for asset in stocklists: 165 | print(asset, start_date, end_date,) 166 | stockfile = os.path.join(stock_path, 167 | u'{}_{}_{}.pickle'.format(asset, 168 | year, 169 | frequence)) 170 | his = import_metadata_from_pickle(stock_path, 171 | u'{}_{}'.format(asset, 172 | year)) 173 | print(his.head(10)) -------------------------------------------------------------------------------- /chapter_04/l03_top1700_60min_download_jqdatasdk.py: -------------------------------------------------------------------------------- 1 | # coding:utf-8 2 | # 3 | # The MIT License (MIT) 4 | # 5 | # Copyright (c) 2018-2020 azai/Rgveda/GolemQuant 6 | # 7 | # Permission is hereby granted, free of charge, to any person obtaining a copy 8 | # of this software and associated documentation files (the "Software"), to deal 9 | # in the Software without restriction, including without limitation the rights 10 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | # copies of the Software, and to permit persons to whom the Software is 12 | # furnished to do so, subject to the following conditions: 13 | # 14 | # The above copyright notice and this permission notice shall be included in 15 | # all 16 | # copies or substantial portions of the Software. 17 | # 18 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 24 | # SOFTWARE. 25 | # 26 | """ 27 | 聚宽小时线(60分钟线)数据下载,范围 Top1700,下载到当前目录 \datastore\kline\stock\ 下 28 | 需开通聚宽本地数据接口,文档:https://www.joinquant.com/help/api/help?name=JQData 29 | 申请地址: https://www.joinquant.com/default/index/sdk#jq-sdk-apply 30 | """ 31 | 32 | import os 33 | import datetime 34 | import pandas as pd 35 | import numpy as np 36 | import time 37 | 38 | from jqdatasdk import ( 39 | auth, 40 | is_auth, 41 | get_query_count, 42 | api as jqapi, 43 | ) 44 | from GolemQ.utils.path import ( 45 | mkdirs, 46 | export_metadata_to_pickle, 47 | import_metadata_from_pickle, 48 | ) 49 | from GolemQ.utils.settings import ( 50 | exists_settings, 51 | input_settings, 52 | load_settings, 53 | save_settings, 54 | ) 55 | try: 56 | import QUANTAXIS as QA 57 | except: 58 | print('PLEASE run "pip install QUANTAXIS" to call these modules') 59 | pass 60 | 61 | if __name__ == '__main__': 62 | # 定义保存云端量化数据源用户名密码的的 pd.DataFrame 结构 63 | password = pd.DataFrame({'host':['jqdatasdk'], 64 | 'username':[None], 65 | 'password':[None]}, 66 | columns=['host', 67 | 'username', 68 | 'password']) 69 | 70 | # 将用户密码token等信息保存到系统的当前用户目录 %userprofile%/.GolemQ 目录下面 71 | pwd_save_file = 'jqdatasdk_pwd.pickle' 72 | if (exists_settings(pwd_save_file)): 73 | password = load_settings(pwd_save_file) 74 | else: 75 | password = input_settings(pattern=password, 76 | filename=pwd_save_file,) 77 | save_settings(pwd_save_file, password) 78 | 79 | #ID是申请时所填写的手机号;Password为聚宽官网登录密码,新申请用户默认为手机号后6位 80 | auth(password.username[0], 81 | password.password[0]) 82 | asset = u'000001.XSHE' 83 | is_auth = is_auth() 84 | 85 | # 查询当日剩余可调用条数 86 | print(get_query_count()) 87 | print(is_auth) 88 | 89 | # 创建数据下载目录 90 | frequence = '60min' 91 | stock_path = mkdirs(os.path.join(mkdirs('datastore'), 92 | 'kline', 'stock', frequence)) 93 | print(stock_path) 94 | frequence = '60min' 95 | 96 | blockname = ['MSCI中国', 'MSCI成份', 'MSCI概念', '三网融合', 97 | '上证180', '上证380', '沪深300', '上证380', 98 | '深证300', '上证50', '上证电信', '电信等权', 99 | '上证100', '上证150', '沪深300', '中证100', 100 | '中证500', '全指消费', '中小板指', '创业板指', 101 | '综企指数', '1000可选', '国证食品', '深证可选', 102 | '深证消费', '深成消费', '中证酒', '中证白酒', 103 | '行业龙头', '白酒', '证券', '消费100', 104 | '消费电子', '消费金融', '富时A50', '银行', 105 | '中小银行', '证券', '军工', '白酒', '啤酒', 106 | '医疗器械', '医疗器械服务', '医疗改革', '医药商业', 107 | '医药电商', '中药', '消费100', '消费电子', 108 | '消费金融', '黄金', '黄金概念', '4G5G', 109 | '5G概念', '生态农业', '生物医药', '生物疫苗', 110 | '机场航运', '数字货币', '文化传媒'] 111 | blockname = list(set(blockname)) 112 | stocklists = QA.QA_fetch_stock_block_adv().get_block(blockname).code 113 | print('批量评估板块成分股:{} Total:{}'.format(blockname, 114 | len(stocklists))) 115 | stocklists = jqapi.normalize_code(stocklists) 116 | 117 | for year in range(2017, 2005, -1): 118 | last_query_count = get_query_count() 119 | print(u'剩余可查询条数', last_query_count) 120 | 121 | start_date = '{}-01-01'.format(year) 122 | end_date = '{}-01-02'.format(year + 1) 123 | for asset in stocklists: 124 | if (last_query_count['spare'] < 1280): 125 | print(u'剩余查询条数已经不足,退出行情查询抓取...') 126 | break 127 | 128 | print(asset, start_date, end_date,) 129 | stockfile = os.path.join(stock_path, 130 | u'{}_{}_{}.pickle'.format(asset, 131 | year, 132 | frequence)) 133 | if os.path.isfile(stockfile): 134 | print('文件已经存在,跳过 ', stockfile) 135 | continue 136 | try: 137 | print(stockfile) 138 | his = jqapi.get_price(asset, 139 | start_date, 140 | end_date, 141 | frequency='60m') 142 | export_metadata_to_pickle(stock_path, 143 | u'{}_{}'.format(asset, 144 | year), 145 | metadata=his) 146 | except Exception as e: 147 | last_query_count = get_query_count() 148 | print(asset, last_query_count, e) 149 | time.sleep(1) 150 | 151 | 152 | for year in range(2017, 2005, -1): 153 | stocklists = [] 154 | for month in range(1, 12): 155 | index_date = '{}-{}-01'.format(year, month) 156 | # 获取特定日期截面的所有沪深300的股票成分 157 | stocklist = jqapi.get_index_stocks('000300.XSHG', 158 | date=index_date) 159 | time.sleep(0.2) 160 | stocklists = stocklists + stocklist 161 | 162 | # 去除重复代码 163 | stocklists = list(set(stocklists)) 164 | print(u'查验数据 {}年 沪深300指数 一共有成分个股:{}个'.format(year, 165 | len(stocklists)), 166 | stocklists) 167 | stocklists = jqapi.normalize_code(stocklists) 168 | 169 | start_date = '{}-01-01'.format(year) 170 | end_date = '{}-01-02'.format(year + 1) 171 | for asset in stocklists: 172 | print(asset, start_date, end_date,) 173 | stockfile = os.path.join(stock_path, 174 | u'{}_{}_{}.pickle'.format(asset, 175 | year, 176 | frequence)) 177 | his = import_metadata_from_pickle(stock_path, 178 | u'{}_{}'.format(asset, 179 | year)) 180 | print(his.head(10)) -------------------------------------------------------------------------------- /chapter_06/l01_plot_a_kline.py: -------------------------------------------------------------------------------- 1 | # coding:utf-8 2 | # 3 | # The MIT License (MIT) 4 | # 5 | # Copyright (c) 2018-2020 azai/Rgveda/GolemQuant 6 | # 7 | # Permission is hereby granted, free of charge, to any person obtaining a copy 8 | # of this software and associated documentation files (the "Software"), to deal 9 | # in the Software without restriction, including without limitation the rights 10 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | # copies of the Software, and to permit persons to whom the Software is 12 | # furnished to do so, subject to the following conditions: 13 | # 14 | # The above copyright notice and this permission notice shall be included in 15 | # all 16 | # copies or substantial portions of the Software. 17 | # 18 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 24 | # SOFTWARE. 25 | # 26 | """ 27 | 绘制最简单的K线图,画K线图是一定要会画的,后续生成CV形态识别K线训练训练集图片都是要自己画图的 28 | """ 29 | 30 | from datetime import datetime as dt 31 | from datetime import timedelta 32 | from datetime import timezone 33 | import pandas as pd 34 | import numpy as np 35 | import time 36 | import matplotlib.pyplot as plt 37 | import mplfinance as mpf 38 | import matplotlib.dates as mdates 39 | 40 | try: 41 | import QUANTAXIS as QA 42 | except: 43 | print('PLEASE run "pip install QUANTAXIS" before run this demo') 44 | pass 45 | 46 | from GolemQ.utils.path import ( 47 | load_cache, 48 | save_cache, 49 | ) 50 | 51 | def ohlc_plot_protype(ohlc_data, code=None, codename=None, title=None): 52 | # 暗色主题 53 | plt.style.use('Solarize_Light2') 54 | 55 | # 正常显示中文字体 56 | plt.rcParams['font.sans-serif'] = ['Microsoft YaHei'] 57 | 58 | # 设定布局 59 | fig = plt.figure(figsize = (22,9)) 60 | plt.subplots_adjust(left=0.04, right=0.96) 61 | if (title is None): 62 | fig.suptitle(u'阿财的 {:s}({:s})量化学习笔记绘制K线DEMO'.format(codename, 63 | code), fontsize=16) 64 | else: 65 | fig.suptitle(title, fontsize=16) 66 | ax1 = fig.add_subplot(111) 67 | 68 | # 绘制K线 69 | ohlc_data = ohlc_data.reset_index([1], drop=False) 70 | mc_stock_cn = mpf.make_marketcolors(up='r',down='g') 71 | s_stock_cn = mpf.make_mpf_style(marketcolors=mc_stock_cn) 72 | mpf.plot(data=ohlc_data, ax=ax1, type='candle', style=s_stock_cn) 73 | 74 | # 设定最标轴时间 75 | datetime_index = ohlc_data.index.get_level_values(level=0).to_series() 76 | DATETIME_LABEL = datetime_index.apply(lambda x: 77 | x.strftime("%Y-%m-%d %H:%M")[2:16]) 78 | ax1.set_xticks(range(0, len(DATETIME_LABEL), 79 | round(len(DATETIME_LABEL) / 12))) 80 | ax1.set_xticklabels(DATETIME_LABEL[::round(len(DATETIME_LABEL) / 12)]) 81 | ax1.grid(True) 82 | return ax1 83 | 84 | 85 | if __name__ == '__main__': 86 | start = dt.now() - timedelta(hours=19200) 87 | end = dt.now(timezone(timedelta(hours=8))) + timedelta(minutes=1) 88 | symbol = '399300' 89 | frequence = '60min' 90 | try: 91 | # 尝试用QA接口读取K线数据 92 | data_min = QA.QA_fetch_index_min_adv('399300', 93 | start='{}'.format(start), 94 | end='{}'.format(end), 95 | frequence=frequence) 96 | if (len(data_min.data) > 100): 97 | fllename = 'kline_{}_{}.pickle'.format(symbol, 98 | frequence) 99 | save_cache(fllename, data_min.data) 100 | ohlc_data = data_min.data.tail(320) 101 | except: 102 | # 没有装QA或者没有数据,尝试读取 pickle 缓存 103 | fllename = 'kline_{}_{}.pickle'.format(symbol, 104 | frequence) 105 | ohlc_data = load_cache(fllename) 106 | 107 | ohlc_plot_protype(ohlc_data, code='399300', codename=u'沪深300') 108 | plt.show() -------------------------------------------------------------------------------- /chapter_06/l02_plot_a_kline_with_ma.py: -------------------------------------------------------------------------------- 1 | # coding:utf-8 2 | # 3 | # The MIT License (MIT) 4 | # 5 | # Copyright (c) 2018-2020 azai/Rgveda/GolemQuant 6 | # 7 | # Permission is hereby granted, free of charge, to any person obtaining a copy 8 | # of this software and associated documentation files (the "Software"), to deal 9 | # in the Software without restriction, including without limitation the rights 10 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | # copies of the Software, and to permit persons to whom the Software is 12 | # furnished to do so, subject to the following conditions: 13 | # 14 | # The above copyright notice and this permission notice shall be included in 15 | # all 16 | # copies or substantial portions of the Software. 17 | # 18 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 24 | # SOFTWARE. 25 | # 26 | """ 27 | 绘制最简单的K线图,画K线图是一定要会画的,以后处理CV形态识别K线训练图片都是要自己画图的,这是基本功。 28 | """ 29 | 30 | from datetime import datetime as dt 31 | from datetime import timedelta 32 | from datetime import timezone 33 | import pandas as pd 34 | import numpy as np 35 | import time 36 | import matplotlib.pyplot as plt 37 | import mplfinance as mpf 38 | import matplotlib.dates as mdates 39 | 40 | try: 41 | import QUANTAXIS as QA 42 | except: 43 | print('PLEASE run "pip install QUANTAXIS" before run this demo') 44 | pass 45 | 46 | from GolemQ.utils.path import ( 47 | load_cache, 48 | save_cache, 49 | ) 50 | 51 | try: 52 | import talib 53 | except: 54 | print('PLEASE run "pip install talib" before call these methods') 55 | pass 56 | 57 | 58 | def ohlc_plot_protype(ohlc_data, code=None, codename=None, title=None): 59 | 60 | # 暗色主题 61 | plt.style.use('Solarize_Light2') 62 | 63 | # 正常显示中文字体 64 | plt.rcParams['font.sans-serif'] = ['Microsoft YaHei'] 65 | 66 | # 设定布局 67 | fig = plt.figure(figsize = (22,9)) 68 | plt.subplots_adjust(left=0.04, right=0.96) 69 | if (title is None): 70 | fig.suptitle(u'阿财的 {:s}({:s})量化学习笔记绘制K线DEMO'.format(codename, 71 | code), fontsize=16) 72 | else: 73 | fig.suptitle(title, fontsize=16) 74 | ax1 = fig.add_subplot(111) 75 | 76 | # 绘制K线 77 | ohlc_data = ohlc_data.reset_index([1], drop=False) 78 | mc_stock_cn = mpf.make_marketcolors(up='r',down='g') 79 | s_stock_cn = mpf.make_mpf_style(marketcolors=mc_stock_cn) 80 | mpf.plot(data=ohlc_data, ax=ax1, type='candle', style=s_stock_cn) 81 | 82 | # 设定最标轴时间 83 | datetime_index = ohlc_data.index.get_level_values(level=0).to_series() 84 | DATETIME_LABEL = datetime_index.apply(lambda x: 85 | x.strftime("%Y-%m-%d %H:%M")[2:16]) 86 | ax1.set_xticks(range(0, len(DATETIME_LABEL), 87 | round(len(DATETIME_LABEL) / 12))) 88 | ax1.set_xticklabels(DATETIME_LABEL[::round(len(DATETIME_LABEL) / 12)]) 89 | ax1.grid(True) 90 | return ax1, DATETIME_LABEL 91 | 92 | 93 | def ma30_cross_func(data): 94 | """ 95 | MA均线金叉指标 96 | """ 97 | MA5 = talib.MA(data.close, 5) 98 | MA10 = talib.MA(data.close, 10) 99 | MA30 = talib.MA(data.close, 30) 100 | MA90 = talib.MA(data.close, 90) 101 | MA120 = talib.MA(data.close, 120) 102 | 103 | MA30_CROSS = pd.DataFrame(np.c_[MA5, 104 | MA10, 105 | MA30, 106 | MA90, 107 | MA120], 108 | columns=['MA5', 109 | 'MA10', 110 | 'MA30', 111 | 'MA90', 112 | 'MA120'], 113 | index=data.index) 114 | 115 | return MA30_CROSS 116 | 117 | 118 | def ohlc_plot_with_ma(ohlc_data, features, 119 | code=None, codename=None, title=None): 120 | """ 121 | 增加 MA 移动平均线 122 | """ 123 | ax1, DATETIME_LABEL = ohlc_plot_protype(ohlc_data, 124 | code='399300', 125 | codename=u'沪深300') 126 | ax1.plot(DATETIME_LABEL, features['MA30'], lw=0.75, 127 | color='blue', alpha=0.6) 128 | ax1.plot(DATETIME_LABEL, 129 | features['MA90'], lw=1, color='crimson', 130 | alpha=0.5) 131 | ax1.plot(DATETIME_LABEL, features['MA120'], lw=1, 132 | color='limegreen', alpha=0.5) 133 | 134 | return ax1 135 | 136 | if __name__ == '__main__': 137 | start = dt.now() - timedelta(hours=19200) 138 | end = dt.now(timezone(timedelta(hours=8))) + timedelta(minutes=1) 139 | symbol = '399300' 140 | frequence = '60min' 141 | try: 142 | # 尝试用QA接口读取K线数据 143 | data_min = QA.QA_fetch_index_min_adv('399300', 144 | start='{}'.format(start), 145 | end='{}'.format(end), 146 | frequence=frequence) 147 | if (len(data_min.data) > 100): 148 | fllename = 'kline_{}_{}.pickle'.format(symbol, 149 | frequence) 150 | save_cache(fllename, data_min.data) 151 | features = ma30_cross_func(data_min.data) 152 | ohlc_data = data_min.data.tail(320) 153 | except: 154 | # 没有装QA或者没有数据,尝试读取 pickle 缓存 155 | fllename = 'kline_{}_{}.pickle'.format(symbol, 156 | frequence) 157 | ohlc_data = load_cache(fllename) 158 | features = ma30_cross_func(ohlc_data) 159 | ohlc_data = ohlc_data.tail(320) 160 | 161 | ohlc_plot_with_ma(ohlc_data, features.tail(320), 162 | code='399300', 163 | codename=u'沪深300') 164 | plt.show() -------------------------------------------------------------------------------- /chapter_06/l03_plot_a_kline_with_macd.py: -------------------------------------------------------------------------------- 1 | # coding:utf-8 2 | # 3 | # The MIT License (MIT) 4 | # 5 | # Copyright (c) 2018-2020 azai/Rgveda/GolemQuant 6 | # 7 | # Permission is hereby granted, free of charge, to any person obtaining a copy 8 | # of this software and associated documentation files (the "Software"), to deal 9 | # in the Software without restriction, including without limitation the rights 10 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | # copies of the Software, and to permit persons to whom the Software is 12 | # furnished to do so, subject to the following conditions: 13 | # 14 | # The above copyright notice and this permission notice shall be included in 15 | # all 16 | # copies or substantial portions of the Software. 17 | # 18 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 24 | # SOFTWARE. 25 | # 26 | """ 27 | 绘制最简单的K线图,画K线图是一定要会画的,以后处理CV形态识别K线训练图片都是要自己画图的,这是基本功。 28 | """ 29 | 30 | from datetime import datetime as dt 31 | from datetime import timedelta 32 | from datetime import timezone 33 | import pandas as pd 34 | import numpy as np 35 | import time 36 | import matplotlib.pyplot as plt 37 | import mplfinance as mpf 38 | import matplotlib.dates as mdates 39 | 40 | try: 41 | import QUANTAXIS as QA 42 | except: 43 | print('PLEASE run "pip install QUANTAXIS" before run this demo') 44 | pass 45 | 46 | from GolemQ.utils.path import ( 47 | load_cache, 48 | save_cache, 49 | ) 50 | 51 | try: 52 | import talib 53 | except: 54 | print('PLEASE run "pip install talib" before call these methods') 55 | pass 56 | 57 | 58 | def TA_MACD(prices:np.ndarray, 59 | fastperiod:int=12, 60 | slowperiod:int=26, 61 | signalperiod:int=9) -> np.ndarray: 62 | ''' 63 | 定义MACD函数 64 | 参数设置: 65 | fastperiod = 12 66 | slowperiod = 26 67 | signalperiod = 9 68 | 69 | 返回: macd - dif, signal - dea, hist * 2 - bar, delta 70 | ''' 71 | macd, signal, hist = talib.MACD(prices, 72 | fastperiod=fastperiod, 73 | slowperiod=slowperiod, 74 | signalperiod=signalperiod) 75 | hist = (macd - signal) * 2 76 | delta = np.r_[np.nan, np.diff(hist)] 77 | return np.c_[macd, signal, hist, delta] 78 | 79 | 80 | def macd_cross_func(data): 81 | """ 82 | 神一样的指标:MACD 83 | """ 84 | MACD = TA_MACD(data.close) 85 | 86 | MACD_CROSS = pd.DataFrame(MACD, 87 | columns=['DIF', 88 | 'DEA', 89 | 'MACD', 90 | 'DELTA'], 91 | index=data.index) 92 | 93 | return MACD_CROSS 94 | 95 | 96 | def ohlc_plot_with_macd(ohlc_data, features, 97 | code=None, codename=None, title=None): 98 | # 暗色主题 99 | plt.style.use('Solarize_Light2') 100 | 101 | # 正常显示中文字体 102 | plt.rcParams['font.sans-serif'] = ['Microsoft YaHei'] 103 | fig = plt.figure(figsize = (16,7)) 104 | plt.subplots_adjust(left=0.05, right=0.97) 105 | if (title is None): 106 | fig.suptitle(u'阿财的 {:s}({:s})量化学习笔记绘制K线DEMO'.format(codename, 107 | code), fontsize=16) 108 | else: 109 | fig.suptitle(title, fontsize=16) 110 | ax1 = plt.subplot2grid((4,3),(0,0), rowspan=3, colspan=3) 111 | ax2 = plt.subplot2grid((4,3),(3,0), rowspan=1, colspan=3, sharex=ax1) 112 | 113 | # 绘制K线 114 | ohlc_data = ohlc_data.reset_index([1], drop=False) 115 | mc_stock_cn = mpf.make_marketcolors(up='r',down='g') 116 | s_stock_cn = mpf.make_mpf_style(marketcolors=mc_stock_cn) 117 | mpf.plot(data=ohlc_data, ax=ax1, type='candle', style=s_stock_cn) 118 | 119 | # 设定最标轴时间 120 | datetime_index = ohlc_data.index.get_level_values(level=0).to_series() 121 | DATETIME_LABEL = datetime_index.apply(lambda x: 122 | x.strftime("%Y-%m-%d %H:%M")[2:16]) 123 | ax1.plot(DATETIME_LABEL, features['MA30'], lw=0.75, 124 | color='blue', alpha=0.6) 125 | ax1.plot(DATETIME_LABEL, features['MA90'], lw=1, 126 | color='crimson', alpha=0.5) 127 | ax1.plot(DATETIME_LABEL, features['MA120'], lw=1, 128 | color='limegreen', alpha=0.5) 129 | ax1.grid(True) 130 | ax2.plot(DATETIME_LABEL, features['DIF'], 131 | color='green', lw=1, label='DIF') 132 | ax2.plot(DATETIME_LABEL, features['DEA'], 133 | color = 'purple', lw = 1, label = 'DEA') 134 | 135 | barlist = ax2.bar(DATETIME_LABEL, features['MACD'], 136 | width = 0.6, label = 'MACD') 137 | for i in range(len(DATETIME_LABEL.index)): 138 | if features['MACD'][i] <= 0: 139 | barlist[i].set_color('g') 140 | else: 141 | barlist[i].set_color('r') 142 | ax2.set(ylabel='MACD(26,12,9)') 143 | 144 | ax2.set_xticks(range(0, len(DATETIME_LABEL), 145 | round(len(DATETIME_LABEL) / 12))) 146 | ax2.set_xticklabels(DATETIME_LABEL[::round(len(DATETIME_LABEL) / 12)], 147 | rotation=15) 148 | ax2.grid(True) 149 | return ax1, ax2, DATETIME_LABEL 150 | 151 | 152 | def ma30_cross_func(data): 153 | """ 154 | MA均线金叉指标 155 | """ 156 | MA5 = talib.MA(data.close, 5) 157 | MA10 = talib.MA(data.close, 10) 158 | MA30 = talib.MA(data.close, 30) 159 | MA90 = talib.MA(data.close, 90) 160 | MA120 = talib.MA(data.close, 120) 161 | 162 | MA30_CROSS = pd.DataFrame(np.c_[MA5, 163 | MA10, 164 | MA30, 165 | MA90, 166 | MA120], 167 | columns=['MA5', 168 | 'MA10', 169 | 'MA30', 170 | 'MA90', 171 | 'MA120'], 172 | index=data.index) 173 | 174 | return MA30_CROSS 175 | 176 | 177 | if __name__ == '__main__': 178 | start = dt.now() - timedelta(hours=19200) 179 | end = dt.now(timezone(timedelta(hours=8))) + timedelta(minutes=1) 180 | symbol = '399300' 181 | frequence = '60min' 182 | try: 183 | # 尝试用QA接口读取K线数据 184 | data_min = QA.QA_fetch_index_min_adv('399300', 185 | start='{}'.format(start), 186 | end='{}'.format(end), 187 | frequence=frequence) 188 | if (len(data_min.data) > 100): 189 | fllename = 'kline_{}_{}.pickle'.format(symbol, 190 | frequence) 191 | save_cache(fllename, data_min.data) 192 | features = pd.concat([ma30_cross_func(data_min.data), 193 | macd_cross_func(data_min.data)], 194 | axis=1, 195 | sort=False) 196 | ohlc_data = data_min.data.tail(320) 197 | except: 198 | # 没有装QA或者没有数据,尝试读取 pickle 缓存 199 | fllename = 'kline_{}_{}.pickle'.format(symbol, 200 | frequence) 201 | ohlc_data = load_cache(fllename) 202 | features = pd.concat([ma30_cross_func(ohlc_data), 203 | macd_cross_func(ohlc_data)], 204 | axis=1, 205 | sort=False) 206 | ohlc_data = ohlc_data.tail(320) 207 | 208 | ohlc_plot_with_macd(ohlc_data, features.tail(320), 209 | code='399300', 210 | codename=u'沪深300') 211 | plt.show() -------------------------------------------------------------------------------- /chapter_06/l04_plot_a_kline_with_boll.py: -------------------------------------------------------------------------------- 1 | # coding:utf-8 2 | # 3 | # The MIT License (MIT) 4 | # 5 | # Copyright (c) 2018-2020 azai/Rgveda/GolemQuant 6 | # 7 | # Permission is hereby granted, free of charge, to any person obtaining a copy 8 | # of this software and associated documentation files (the "Software"), to deal 9 | # in the Software without restriction, including without limitation the rights 10 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | # copies of the Software, and to permit persons to whom the Software is 12 | # furnished to do so, subject to the following conditions: 13 | # 14 | # The above copyright notice and this permission notice shall be included in 15 | # all 16 | # copies or substantial portions of the Software. 17 | # 18 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 24 | # SOFTWARE. 25 | # 26 | """ 27 | 绘制最简单的K线图,画K线图是一定要会画的,以后处理CV形态识别K线训练图片都是要自己画图的,这是基本功。 28 | """ 29 | 30 | from datetime import datetime as dt 31 | from datetime import timedelta 32 | from datetime import timezone 33 | import pandas as pd 34 | import numpy as np 35 | import time 36 | import matplotlib.pyplot as plt 37 | import mplfinance as mpf 38 | import matplotlib.dates as mdates 39 | 40 | try: 41 | import QUANTAXIS as QA 42 | except: 43 | print('PLEASE run "pip install QUANTAXIS" before run this demo') 44 | pass 45 | 46 | from GolemQ.utils.path import ( 47 | load_cache, 48 | save_cache, 49 | ) 50 | 51 | try: 52 | import talib 53 | except: 54 | print('PLEASE run "pip install talib" before call these methods') 55 | pass 56 | 57 | 58 | def ohlc_plot_with_boll(ohlc_data, features, 59 | code=None, codename=None, title=None): 60 | 61 | # 暗色主题 62 | plt.style.use('Solarize_Light2') 63 | 64 | # 正常显示中文字体 65 | plt.rcParams['font.sans-serif'] = ['Microsoft YaHei'] 66 | fig = plt.figure(figsize = (16,7)) 67 | plt.subplots_adjust(left=0.05, right=0.97) 68 | if (title is None): 69 | fig.suptitle(u'阿财的 {:s}({:s})量化学习笔记绘制K线DEMO'.format(codename, 70 | code), fontsize=16) 71 | else: 72 | fig.suptitle(title, fontsize=16) 73 | ax1 = plt.subplot2grid((4,3),(0,0), rowspan=3, colspan=3) 74 | ax2 = plt.subplot2grid((4,3),(3,0), rowspan=1, colspan=3, sharex=ax1) 75 | 76 | # 绘制K线 77 | ohlc_data = ohlc_data.reset_index([1], drop=False) 78 | mc_stock_cn = mpf.make_marketcolors(up='r',down='g') 79 | s_stock_cn = mpf.make_mpf_style(marketcolors=mc_stock_cn) 80 | mpf.plot(data=ohlc_data, ax=ax1, type='candle', style=s_stock_cn) 81 | 82 | # 设定最标轴时间 83 | datetime_index = ohlc_data.index.get_level_values(level=0).to_series() 84 | DATETIME_LABEL = datetime_index.apply(lambda x: 85 | x.strftime("%Y-%m-%d %H:%M")[2:16]) 86 | 87 | ax1.plot(DATETIME_LABEL, features['MA30'], lw=0.75, 88 | color='blue', alpha=0.6) 89 | ax1.plot(DATETIME_LABEL, features['MA90'], lw=1, 90 | color='crimson', alpha=0.5) 91 | ax1.plot(DATETIME_LABEL, features['MA120'], lw=1, 92 | color='limegreen', alpha=0.5) 93 | ax1.plot(DATETIME_LABEL, features['BOLL_UB'], lw=0.75, 94 | color='cyan', alpha=0.6) 95 | ax1.plot(DATETIME_LABEL, features['BOLL_LB'], lw=0.75, 96 | color='fuchsia', alpha=0.6) 97 | ax1.plot(DATETIME_LABEL, features['BOLL'], lw=0.75, 98 | color='purple', alpha=0.6) 99 | ax1.fill_between(DATETIME_LABEL, 100 | features['BOLL_UB'], 101 | features['BOLL_LB'], 102 | color='lightskyblue', alpha=0.15) 103 | ax1.grid(True) 104 | 105 | ax2.plot(DATETIME_LABEL, features['DIF'], 106 | color='green', lw=1, label='DIF') 107 | ax2.plot(DATETIME_LABEL, features['DEA'], 108 | color = 'purple', lw = 1, label = 'DEA') 109 | 110 | barlist = ax2.bar(DATETIME_LABEL, features['MACD'], 111 | width = 0.6, label = 'MACD') 112 | for i in range(len(DATETIME_LABEL.index)): 113 | if features['MACD'][i] <= 0: 114 | barlist[i].set_color('g') 115 | else: 116 | barlist[i].set_color('r') 117 | ax2.set(ylabel='MACD(26,12,9)') 118 | 119 | ax2.set_xticks(range(0, len(DATETIME_LABEL), 120 | round(len(DATETIME_LABEL) / 12))) 121 | ax2.set_xticklabels(DATETIME_LABEL[::round(len(DATETIME_LABEL) / 12)], 122 | rotation=15) 123 | ax2.grid(True) 124 | 125 | 126 | return ax1, ax2, DATETIME_LABEL 127 | 128 | 129 | def TA_MACD(prices:np.ndarray, 130 | fastperiod:int=12, 131 | slowperiod:int=26, 132 | signalperiod:int=9) -> np.ndarray: 133 | ''' 134 | 定义MACD函数 135 | 参数设置: 136 | fastperiod = 12 137 | slowperiod = 26 138 | signalperiod = 9 139 | 140 | 返回: macd - dif, signal - dea, hist * 2 - bar, delta 141 | ''' 142 | macd, signal, hist = talib.MACD(prices, 143 | fastperiod=fastperiod, 144 | slowperiod=slowperiod, 145 | signalperiod=signalperiod) 146 | hist = (macd - signal) * 2 147 | delta = np.r_[np.nan, np.diff(hist)] 148 | return np.c_[macd, signal, hist, delta] 149 | 150 | 151 | def macd_cross_func(data): 152 | """ 153 | 神一样的指标:MACD 154 | """ 155 | MACD = TA_MACD(data.close) 156 | 157 | MACD_CROSS = pd.DataFrame(MACD, 158 | columns=['DIF', 159 | 'DEA', 160 | 'MACD', 161 | 'DELTA'], 162 | index=data.index) 163 | 164 | return MACD_CROSS 165 | 166 | 167 | def ma30_cross_func(data): 168 | """ 169 | MA均线金叉指标 170 | """ 171 | MA5 = talib.MA(data.close, 5) 172 | MA10 = talib.MA(data.close, 10) 173 | MA30 = talib.MA(data.close, 30) 174 | MA90 = talib.MA(data.close, 90) 175 | MA120 = talib.MA(data.close, 120) 176 | 177 | MA30_CROSS = pd.DataFrame(np.c_[MA5, 178 | MA10, 179 | MA30, 180 | MA90, 181 | MA120], 182 | columns=['MA5', 183 | 'MA10', 184 | 'MA30', 185 | 'MA90', 186 | 'MA120'], 187 | index=data.index) 188 | 189 | return MA30_CROSS 190 | 191 | 192 | def TA_BBANDS(prices:np.ndarray, 193 | timeperiod:int=5, 194 | nbdevup:int=2, 195 | nbdevdn:int=2, 196 | matype:int=0) -> np.ndarray: 197 | ''' 198 | 定义RSI函数 199 | 参数设置: 200 | timeperiod = 5 201 | nbdevup = 2 202 | nbdevdn = 2 203 | 204 | 返回: up, middle, low 205 | ''' 206 | up, middle, low = talib.BBANDS(prices, 207 | timeperiod, 208 | nbdevup, 209 | nbdevdn, 210 | matype) 211 | ch = (up - low) / middle 212 | delta = np.r_[np.nan, np.diff(ch)] 213 | return np.c_[up, middle, low, ch, delta] 214 | 215 | 216 | def boll_cross_func(data): 217 | """ 218 | 布林线和K线金叉死叉 状态分析 219 | """ 220 | BBANDS = TA_BBANDS(data.close, timeperiod=20, nbdevup=2) 221 | BOLL_CROSS = pd.DataFrame(BBANDS, 222 | columns=['BOLL_UB', 223 | 'BOLL', 224 | 'BOLL_LB', 225 | 'BOLL_CHANNEL', 226 | 'BOLL_DELTA'], 227 | index=data.index) 228 | data = data.assign(BOLL_MA=BBANDS[:,1]) 229 | 230 | return BOLL_CROSS 231 | 232 | 233 | if __name__ == '__main__': 234 | start = dt.now() - timedelta(hours=19200) 235 | end = dt.now(timezone(timedelta(hours=8))) + timedelta(minutes=1) 236 | symbol = '399300' 237 | frequence = '60min' 238 | try: 239 | # 尝试用QA接口读取K线数据 240 | data_min = QA.QA_fetch_index_min_adv('399300', 241 | start='{}'.format(start), 242 | end='{}'.format(end), 243 | frequence=frequence) 244 | if (len(data_min.data) > 100): 245 | fllename = 'kline_{}_{}.pickle'.format(symbol, 246 | frequence) 247 | save_cache(fllename, data_min.data) 248 | features = pd.concat([ma30_cross_func(data_min.data), 249 | macd_cross_func(data_min.data), 250 | boll_cross_func(data_min.data)], 251 | axis=1, 252 | sort=False) 253 | ohlc_data = data_min.data.tail(320) 254 | except: 255 | # 没有装QA或者没有保存数据,尝试读取 pickle 缓存 256 | fllename = 'kline_{}_{}.pickle'.format(symbol, 257 | frequence) 258 | ohlc_data = load_cache(fllename) 259 | features = pd.concat([ma30_cross_func(ohlc_data), 260 | macd_cross_func(ohlc_data), 261 | boll_cross_func(ohlc_data)], 262 | axis=1, 263 | sort=False) 264 | ohlc_data = ohlc_data.tail(320) 265 | 266 | ohlc_plot_with_boll(ohlc_data, features.tail(320), 267 | code='399300', 268 | codename=u'沪深300') 269 | plt.show() -------------------------------------------------------------------------------- /chapter_07/l04_robust_peak_point.py: -------------------------------------------------------------------------------- 1 | # coding:utf-8 2 | # 3 | # The MIT License (MIT) 4 | # 5 | # Copyright (c) 2018-2020 azai/Rgveda/GolemQuant 6 | # 7 | # Permission is hereby granted, free of charge, to any person obtaining a copy 8 | # of this software and associated documentation files (the "Software"), to deal 9 | # in the Software without restriction, including without limitation the rights 10 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | # copies of the Software, and to permit persons to whom the Software is 12 | # furnished to do so, subject to the following conditions: 13 | # 14 | # The above copyright notice and this permission notice shall be included in 15 | # all 16 | # copies or substantial portions of the Software. 17 | # 18 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 24 | # SOFTWARE. 25 | # 26 | """ 27 | Robust peak detection algorithm (using z-scores) 28 | 29 | 自带鲁棒性极值点识别,利用方差和ZSCORE进行时间序列极值检测。 30 | """ 31 | 32 | from datetime import datetime as dt 33 | from datetime import timedelta 34 | from datetime import timezone 35 | import pandas as pd 36 | import numpy as np 37 | import time 38 | 39 | from jqdatasdk import ( 40 | auth, 41 | is_auth, 42 | get_query_count, 43 | api as jqapi, 44 | ) 45 | from GolemQ.utils.path import ( 46 | mkdirs, 47 | export_metadata_to_pickle, 48 | import_metadata_from_pickle, 49 | ) 50 | from GolemQ.utils.settings import ( 51 | load_settings, 52 | save_settings, 53 | ) 54 | try: 55 | import QUANTAXIS as QA 56 | except: 57 | print('PLEASE run "pip install QUANTAXIS" to call these modules') 58 | pass 59 | 60 | if __name__ == '__main__': 61 | #password = pd.DataFrame({'host':['jqdatasdk'], 62 | # 'username':['13981813381'], 63 | # 'password':['813381']}, columns=['host', 64 | # 'username', 65 | # 'password']) 66 | # 用上面的代码保存密码到用户配置 .GolemQ 目录下面 67 | password = load_settings('password.pickle') 68 | auth(password.username[0], password.password[0]) #ID是申请时所填写的手机号;Password为聚宽官网登录密码,新申请用户默认为手机号后6位 69 | asset = u'000001.XSHE' 70 | is_auth = is_auth() 71 | 72 | # 查询当日剩余可调用条数 73 | print(get_query_count()) 74 | print(is_auth) 75 | codelist = ['000876'] 76 | indexlist = [ '000001.XSHG', '000002.XSHG', '000003.XSHG', '000004.XSHG', 77 | '000005.XSHG', '000006.XSHG', '000007.XSHG', '000009.XSHG', 78 | '000009.XSHG', '000010.XSHG', '000015.XSHG', '000016.XSHG', 79 | '000036.XSHG', '000037.XSHG', '000038.XSHG', '000039.XSHG', 80 | '000040.XSHG', '000300.XSHG', '000112.XSHG', '000133.XSHG', 81 | '000903.XSHG', '000905.XSHG', '000906.XSHG', 82 | '399001', '399006', 83 | '000989.XSHG', '000990.XSHG', '000991.XSHG', '000992.XSHG', 84 | '000993.XSHG', '000994.XSHG', 85 | '513030', '399684', '159934', '512000', 86 | '159987', '399616', '510050', '513100', 87 | '510850', '518880', '510180', '159916', 88 | '512980', '512090', '515000', 89 | '510900', '512910', '513050', '510300', 90 | '399384', '510810', '399987', '159905', 91 | '399396', '399997', '159919', 92 | '159941', '159920', ] 93 | indexlist = jqapi.normalize_code(indexlist) 94 | code = codelist[0] 95 | 96 | # 创建数据下载目录 97 | index_path = mkdirs(os.path.join(mkdirs('datastore'), 'kline', 'index')) 98 | print(index_path) 99 | frequence = '60min' 100 | 101 | for year in range(2017, 2005, -1): 102 | start_date = '{}-01-01'.format(year) 103 | end_date = '{}-01-02'.format(year + 1) 104 | for asset in indexlist: 105 | print(asset, start_date, end_date,) 106 | indexfile = os.path.join(index_path, u'{}_{}_{}.pickle'.format(asset, year, frequence)) 107 | if os.path.isfile(indexfile ): 108 | print('文件已经存在,跳过 ', indexfile) 109 | continue 110 | try: 111 | print(indexfile ) 112 | his = jqapi.get_price(asset, start_date, end_date, frequency='60m') 113 | export_metadata_to_pickle(index_path, u'{}_{}'.format(asset, year), metadata=his) 114 | #data_day = QA.QA_fetch_stock_min_adv(codelist, 115 | # start='2019-01-01', 116 | # end='2020-08-28', 117 | # frequence='60min') 118 | #his = data_day.data 119 | except Exception as e: 120 | print(asset, e) 121 | time.sleep(1) 122 | 123 | 124 | for year in range(2017, 2005, -1): 125 | start_date = '{}-01-01'.format(year) 126 | end_date = '{}-01-02'.format(year + 1) 127 | for asset in indexlist: 128 | print(asset, start_date, end_date,) 129 | indexfile = os.path.join(index_path, u'{}_{}_{}.pickle'.format(asset, year, frequence)) 130 | his = import_metadata_from_pickle(index_path, u'{}_{}'.format(asset, year)) 131 | print(his.head(10)) 132 | 133 | 134 | # 创建数据下载目录 135 | stock_path = mkdirs(os.path.join(mkdirs('datastore'), 'kline', 'stock')) 136 | print(stock_path) 137 | frequence = '60min' 138 | 139 | stocklist = ['002230', '600900', '300560', '300146', 140 | '002271', '603129', '002557', '002603', 141 | '600161', '600477', '000661', '600519', 142 | '603520', '002503', '000157', '002179', 143 | '600585', '600298', '600104', '002594', 144 | '603288', '300760', '300715', '002007', 145 | '002258', '300433', '300059', '600612', 146 | '603515', '603486', '002352', '300314', 147 | '600332', '601138', '600522', '600031', 148 | '600436', '603444', '601933', '601611', 149 | '000876', '002714', '002415', '601558', 150 | '603517', '000895', '603259', '002831', 151 | '000333', '300498', '601100', '600030', 152 | '600188', '600352', '600009', '002382', 153 | '600887', '601888', '600309', '000858', 154 | '002475', '603713', '300750', '002050', 155 | '600547', '600660', '600570', '603899', 156 | '002705', '300015', '601877', '000568', 157 | '600486', '300144', '600276', '000651', 158 | '601318', '600563', '600066', '300122', 159 | '300263', '601857', '600600', '000538', 160 | '300325', '000671', '600036'] 161 | #stocklist = [] 162 | stocklist = jqapi.normalize_code(stocklist) 163 | 164 | for year in range(2017, 2005, -1): 165 | start_date = '{}-01-01'.format(year) 166 | end_date = '{}-01-02'.format(year + 1) 167 | for asset in stocklist: 168 | print(asset, start_date, end_date,) 169 | stockfile = os.path.join(stock_path, u'{}_{}_{}.pickle'.format(asset, year, frequence)) 170 | if os.path.isfile(stockfile ): 171 | print('文件已经存在,跳过 ', stockfile) 172 | continue 173 | try: 174 | print(stockfile ) 175 | his = jqapi.get_price(asset, start_date, end_date, frequency='60m') 176 | export_metadata_to_pickle(stock_path, u'{}_{}'.format(asset, year), metadata=his) 177 | #data_day = QA.QA_fetch_stock_min_adv(codelist, 178 | # start='2019-01-01', 179 | # end='2020-08-28', 180 | # frequence='60min') 181 | #his = data_day.data 182 | except Exception as e: 183 | print(asset, e) 184 | time.sleep(1) 185 | 186 | 187 | for year in range(2017, 2005, -1): 188 | start_date = '{}-01-01'.format(year) 189 | end_date = '{}-01-02'.format(year + 1) 190 | for asset in stocklist: 191 | print(asset, start_date, end_date,) 192 | stockfile = os.path.join(stock_path, u'{}_{}_{}.pickle'.format(asset, year, frequence)) 193 | his = import_metadata_from_pickle(stock_path, u'{}_{}'.format(asset, year)) 194 | print(his.head(10)) -------------------------------------------------------------------------------- /samples/data/cache/kline_399300_60min.pickle: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Rgveda/996Quant/e36a8e1e684d0cd21bcb70657e349a3d65cfd706/samples/data/cache/kline_399300_60min.pickle --------------------------------------------------------------------------------