├── instock
├── trade
│ ├── __init__.py
│ ├── robot
│ │ ├── engine
│ │ │ ├── __init__.py
│ │ │ ├── event_engine.py
│ │ │ └── .gitignore
│ │ ├── infrastructure
│ │ │ ├── __init__.py
│ │ │ ├── strategy_template.py
│ │ │ ├── strategy_wrapper.py
│ │ │ ├── default_handler.py
│ │ │ └── .gitignore
│ │ ├── __init__.py
│ │ └── .gitignore
│ ├── strategies
│ │ ├── __init__.py
│ │ ├── stagging.py
│ │ ├── stratey1.py
│ │ └── .gitignore
│ ├── trade_service.py
│ └── .gitignore
├── core
│ ├── crawling
│ │ ├── __init__.py
│ │ ├── stock_selection.py
│ │ ├── stock_fhps_em.py
│ │ └── stock_cpbd.py
│ ├── __init__.py
│ ├── kline
│ │ ├── __init__.py
│ │ ├── .gitignore
│ │ └── cyq.py
│ ├── backtest
│ │ ├── __init__.py
│ │ ├── rate_stats.py
│ │ └── .gitignore
│ ├── indicator
│ │ ├── __init__.py
│ │ └── .gitignore
│ ├── pattern
│ │ ├── __init__.py
│ │ ├── pattern_recognitions.py
│ │ └── .gitignore
│ ├── strategy
│ │ ├── __init__.py
│ │ ├── turtle_trade.py
│ │ ├── keep_increasing.py
│ │ ├── high_tight_flag.py
│ │ ├── low_backtrace_increase.py
│ │ ├── climax_limitdown.py
│ │ ├── enter.py
│ │ ├── breakthrough_platform.py
│ │ ├── low_atr.py
│ │ ├── parking_apron.py
│ │ ├── backtrace_ma250.py
│ │ └── .gitignore
│ ├── singleton_trade_date.py
│ ├── web_module_data.py
│ ├── singleton_stock.py
│ └── .gitignore
├── web
│ ├── templates
│ │ ├── common
│ │ │ ├── footer.html
│ │ │ ├── header.html
│ │ │ ├── meta.html
│ │ │ └── left_menu.html
│ │ ├── layout
│ │ │ ├── indicators.html
│ │ │ ├── default.html
│ │ │ ├── indicators-main.html
│ │ │ └── main.html
│ │ └── stock_indicators.html
│ ├── static
│ │ ├── img
│ │ │ ├── favicon.ico
│ │ │ └── favicon16.ico
│ │ ├── fonts
│ │ │ ├── fontawesome-webfont.ttf
│ │ │ ├── fontawesome-webfont.woff
│ │ │ └── fontawesome-webfont.woff2
│ │ └── js
│ │ │ ├── bootstrap-datepicker.zh-CN.min.js
│ │ │ ├── ace-extra.min.js
│ │ │ └── FileSaver.js
│ ├── __init__.py
│ ├── base.py
│ ├── dataIndicatorsHandler.py
│ ├── dataTableHandler.py
│ ├── web_service.py
│ └── .gitignore
├── __init__.py
├── job
│ ├── __init__.py
│ ├── basic_data_after_close_daily_job.py
│ ├── selection_data_daily_job.py
│ ├── execute_daily_job.py
│ ├── init_job.py
│ ├── basic_data_daily_job.py
│ ├── klinepattern_data_daily_job.py
│ ├── strategy_data_daily_job.py
│ ├── backtest_data_daily_job.py
│ ├── .gitignore
│ └── indicators_data_daily_job.py
├── lib
│ ├── __init__.py
│ ├── version.py
│ ├── singleton_type.py
│ ├── run_template.py
│ ├── .gitignore
│ ├── trade_time.py
│ └── crypto_aes.py
├── config
│ ├── trade_client.json
│ └── .gitignore
├── bin
│ ├── restart_web.sh
│ ├── run_trade.bat
│ ├── run_web.sh
│ ├── run_web.bat
│ ├── run_cron.sh
│ ├── run_job.sh
│ └── run_job.bat
└── .gitignore
├── docker
├── .dockerignore
├── build.sh
├── Dockerfile
└── .gitignore
├── img
├── 00.jpg
├── 01.jpg
├── 03.jpg
├── 04.jpg
├── 05.jpg
├── 06.jpg
├── 07.jpg
├── 08.jpg
├── 09.jpg
├── 11.jpg
├── 12.jpg
├── 13.jpg
├── a1.jpg
└── a3.jpg
├── cron
├── cron.hourly
│ └── run_hourly
├── cron.workdayly
│ └── run_workdayly
└── cron.monthly
│ └── run_monthly
├── requirements.txt
├── .github
└── workflows
│ ├── docker-image.yml
│ └── azure-container-webapp.yml
├── supervisor
└── supervisord.conf
└── .gitignore
/instock/trade/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/instock/core/crawling/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/instock/trade/robot/engine/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/instock/trade/strategies/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/instock/trade/robot/infrastructure/__init__.py:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/instock/web/templates/common/footer.html:
--------------------------------------------------------------------------------
1 | {% block footer %}
2 | {% end %}
--------------------------------------------------------------------------------
/instock/web/templates/common/header.html:
--------------------------------------------------------------------------------
1 | {% block header %}
2 | {% end %}
--------------------------------------------------------------------------------
/docker/.dockerignore:
--------------------------------------------------------------------------------
1 | .git
2 | .idea
3 | *.bat
4 | *.md
5 | requirements.txt
--------------------------------------------------------------------------------
/img/00.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ethqunzhong/InStock/HEAD/img/00.jpg
--------------------------------------------------------------------------------
/img/01.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ethqunzhong/InStock/HEAD/img/01.jpg
--------------------------------------------------------------------------------
/img/03.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ethqunzhong/InStock/HEAD/img/03.jpg
--------------------------------------------------------------------------------
/img/04.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ethqunzhong/InStock/HEAD/img/04.jpg
--------------------------------------------------------------------------------
/img/05.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ethqunzhong/InStock/HEAD/img/05.jpg
--------------------------------------------------------------------------------
/img/06.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ethqunzhong/InStock/HEAD/img/06.jpg
--------------------------------------------------------------------------------
/img/07.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ethqunzhong/InStock/HEAD/img/07.jpg
--------------------------------------------------------------------------------
/img/08.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ethqunzhong/InStock/HEAD/img/08.jpg
--------------------------------------------------------------------------------
/img/09.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ethqunzhong/InStock/HEAD/img/09.jpg
--------------------------------------------------------------------------------
/img/11.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ethqunzhong/InStock/HEAD/img/11.jpg
--------------------------------------------------------------------------------
/img/12.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ethqunzhong/InStock/HEAD/img/12.jpg
--------------------------------------------------------------------------------
/img/13.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ethqunzhong/InStock/HEAD/img/13.jpg
--------------------------------------------------------------------------------
/img/a1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ethqunzhong/InStock/HEAD/img/a1.jpg
--------------------------------------------------------------------------------
/img/a3.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ethqunzhong/InStock/HEAD/img/a3.jpg
--------------------------------------------------------------------------------
/instock/web/static/img/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ethqunzhong/InStock/HEAD/instock/web/static/img/favicon.ico
--------------------------------------------------------------------------------
/instock/web/static/img/favicon16.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ethqunzhong/InStock/HEAD/instock/web/static/img/favicon16.ico
--------------------------------------------------------------------------------
/instock/web/templates/layout/indicators.html:
--------------------------------------------------------------------------------
1 | {% extends "../common/meta.html" %}
2 |
3 | {% extends "indicators-main.html" %}
--------------------------------------------------------------------------------
/instock/__init__.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | # -*- coding: utf-8 -*-
3 |
4 | __author__ = 'myh '
5 | __date__ = '2023/4/3 '
6 |
--------------------------------------------------------------------------------
/instock/core/__init__.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | # -*- coding: utf-8 -*-
3 |
4 | __author__ = 'myh '
5 | __date__ = '2023/4/3 '
6 |
--------------------------------------------------------------------------------
/instock/job/__init__.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | # -*- coding: utf-8 -*-
3 |
4 | __author__ = 'myh '
5 | __date__ = '2023/4/3 '
6 |
--------------------------------------------------------------------------------
/instock/lib/__init__.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | # -*- coding: utf-8 -*-
3 |
4 | __author__ = 'myh '
5 | __date__ = '2023/4/3 '
6 |
--------------------------------------------------------------------------------
/instock/web/__init__.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | # -*- coding: utf-8 -*-
3 |
4 | __author__ = 'myh '
5 | __date__ = '2023/4/3 '
6 |
--------------------------------------------------------------------------------
/instock/config/trade_client.json:
--------------------------------------------------------------------------------
1 | {
2 | "user": "888888888888",
3 | "password": "888888",
4 | "exe_path": "C:/gfzqrzrq/xiadan.exe"
5 | }
--------------------------------------------------------------------------------
/instock/core/kline/__init__.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | # -*- coding: utf-8 -*-
3 |
4 | __author__ = 'myh '
5 | __date__ = '2023/4/6 '
6 |
--------------------------------------------------------------------------------
/instock/trade/robot/__init__.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | # -*- coding: utf-8 -*-
3 |
4 | __author__ = 'myh '
5 | __date__ = '2023/4/13 '
6 |
--------------------------------------------------------------------------------
/instock/core/backtest/__init__.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | # -*- coding: utf-8 -*-
3 |
4 | __author__ = 'myh '
5 | __date__ = '2023/3/13 '
6 |
--------------------------------------------------------------------------------
/instock/core/indicator/__init__.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | # -*- coding: utf-8 -*-
3 |
4 | __author__ = 'mmm '
5 | __date__ = '2023/3/10 '
6 |
--------------------------------------------------------------------------------
/instock/core/pattern/__init__.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | # -*- coding: utf-8 -*-
3 |
4 | __author__ = 'myh '
5 | __date__ = '2023/3/13 '
6 |
--------------------------------------------------------------------------------
/instock/core/strategy/__init__.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | # -*- coding: utf-8 -*-
3 |
4 | __author__ = 'mmm '
5 | __date__ = '2023/3/10 '
6 |
--------------------------------------------------------------------------------
/instock/web/static/fonts/fontawesome-webfont.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ethqunzhong/InStock/HEAD/instock/web/static/fonts/fontawesome-webfont.ttf
--------------------------------------------------------------------------------
/instock/web/static/fonts/fontawesome-webfont.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ethqunzhong/InStock/HEAD/instock/web/static/fonts/fontawesome-webfont.woff
--------------------------------------------------------------------------------
/instock/bin/restart_web.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | ps -ef | grep python3 | grep '/data/InStock/instock/web/web_service.py' | awk '{print$2}' | xargs kill -9
4 |
--------------------------------------------------------------------------------
/instock/web/static/fonts/fontawesome-webfont.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ethqunzhong/InStock/HEAD/instock/web/static/fonts/fontawesome-webfont.woff2
--------------------------------------------------------------------------------
/instock/bin/run_trade.bat:
--------------------------------------------------------------------------------
1 | chcp 65001
2 | @echo off
3 | cd %~dp0
4 | cd ..
5 | cd trade
6 | python trade_service.py
7 | echo ------交易服务已启动,请不要关闭------
8 | pause
9 | exit
10 |
--------------------------------------------------------------------------------
/instock/lib/version.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | # -*- coding: utf-8 -*-
3 |
4 | __author__ = 'myh '
5 | __date__ = '2023/3/11 '
6 |
7 | __version__ = "4.0.0"
8 | # 每次发布时候更新。
9 |
--------------------------------------------------------------------------------
/instock/bin/run_web.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | /usr/local/bin/python3 /data/InStock/instock/web/web_service.py
4 |
5 | echo ------Web服务已启动 请不要关闭------
6 | echo 访问地址 : http://localhost:9988/
7 |
--------------------------------------------------------------------------------
/instock/bin/run_web.bat:
--------------------------------------------------------------------------------
1 | chcp 65001
2 | @echo off
3 | cd %~dp0
4 | cd ..
5 | cd web
6 | python web_service.py
7 | echo ------Web服务已启动,请不要关闭------
8 | echo 访问地址 : http://localhost:9988/
9 | pause
10 | exit
11 |
--------------------------------------------------------------------------------
/cron/cron.hourly/run_hourly:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | /usr/local/bin/python3 /data/InStock/instock/job/basic_data_daily_job.py
4 | #mkdir -p /data/logs
5 | #DATE=`date +%Y-%m-%d:%H:%M:%S`
6 | #echo $DATE >> /data/logs/hourly.log
--------------------------------------------------------------------------------
/cron/cron.workdayly/run_workdayly:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | /usr/local/bin/python3 /data/InStock/instock/job/execute_daily_job.py
4 |
5 | #mkdir -p /data/logs
6 | #DATE=`date +%Y-%m-%d:%H:%M:%S`
7 | #echo $DATE >> /data/logs/workdayly.log
--------------------------------------------------------------------------------
/instock/web/templates/layout/default.html:
--------------------------------------------------------------------------------
1 | {% extends "../common/meta.html" %}
2 | {% extends "../common/header.html" %}
3 | {% extends "../common/footer.html" %}
4 | {% extends "../common/left_menu.html" %}
5 |
6 | {% extends "main.html" %}
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | numpy==2.2.3
2 | pandas==2.2.3
3 | py_mini_racer==0.6.0
4 | mini-racer==0.12.4
5 | TA_Lib==0.6.3
6 | arrow==1.3.0
7 | bokeh==3.6.2
8 | PyMySQL==1.1.1
9 | requests==2.32.3
10 | Logbook==1.8.0
11 | SQLAlchemy==2.0.38
12 | tornado==6.4.2
13 | tqdm==4.67.1
14 | easytrader==0.23.0
15 | beautifulsoup4==4.13.3
16 | pycryptodome==3.21.0
17 | python_dateutil==2.9.0.post0
--------------------------------------------------------------------------------
/instock/bin/run_cron.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | export PYTHONIOENCODING=utf-8
4 | export LANG=zh_CN.UTF-8
5 | export PYTHONPATH=/data/InStock
6 | export LC_CTYPE=zh_CN.UTF-8
7 |
8 | # 环境变量输出
9 | # https://stackoverflow.com/questions/27771781/how-can-i-access-docker-set-environment-variables-from-a-cron-job
10 | printenv | grep -v "no_proxy" >> /etc/environment
11 |
12 | #启动cron服务。在前台
13 | /usr/sbin/cron -f
--------------------------------------------------------------------------------
/.github/workflows/docker-image.yml:
--------------------------------------------------------------------------------
1 | 姓名:名称:Docker 镜像 CI
2 |
3 | on:
4 | push:
5 | branches: [ 分支:[“主”]"master" ]
6 | pull_request:
7 | branches: [ 分支:[“主”]"master" ]
8 |
9 | jobs:
10 |
11 | build:
12 |
13 | runs-on: 运行:ubuntu-latest
14 |
15 | steps:
16 | - uses: - 使用:actions/checkout@v3
17 | - name: - 名称:构建 Docker 镜像
18 | run: 运行: docker build 。--file Dockerfile --tag my-image-name:$(日期 +%s): $(日期 +%s)
19 |
--------------------------------------------------------------------------------
/instock/web/static/js/bootstrap-datepicker.zh-CN.min.js:
--------------------------------------------------------------------------------
1 | !function(a){a.fn.datepicker.dates["zh-CN"]={days:["星期日","星期一","星期二","星期三","星期四","星期五","星期六"],daysShort:["周日","周一","周二","周三","周四","周五","周六"],daysMin:["日","一","二","三","四","五","六"],months:["一月","二月","三月","四月","五月","六月","七月","八月","九月","十月","十一月","十二月"],monthsShort:["1月","2月","3月","4月","5月","6月","7月","8月","9月","10月","11月","12月"],today:"今天",monthsTitle:"选择月份",clear:"清除",format:"yyyy-mm-dd",titleFormat:"yyyy年mm月",weekStart:1}}(jQuery);
--------------------------------------------------------------------------------
/cron/cron.monthly/run_monthly:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | #清除缓存数据
4 | rm -rf /data/InStock/instock/cache/hist/*
5 | #MONTH=`date -d '' +%Y%m`
6 | #cd /data/InStock/instock/cache/hist && rm -rf !(${MONTH})
7 | #DATE=`date -d '' +%Y-%m-%d`
8 | #DATE_1=`date -d '-1 days' +%Y-%m-%d`
9 | #DATE_2=`date -d '-2 days' +%Y-%m-%d`
10 | #cd /data/InStock/instock/cache/hist/${MONTH} && rm -rf !(${DATE}|${DATE_1}|${DATE_2})
11 |
12 | #mkdir -p /data/logs
13 | #DATE=`date +%Y-%m-%d:%H:%M:%S`
14 | #echo $DATE >> /data/logs/monthly.log
15 |
--------------------------------------------------------------------------------
/instock/lib/singleton_type.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | # -*- coding: utf-8 -*-
3 |
4 |
5 | from threading import RLock
6 |
7 |
8 | __author__ = 'myh '
9 | __date__ = '2023/3/10 '
10 |
11 |
12 | class singleton_type(type):
13 | single_lock = RLock()
14 |
15 | def __call__(cls, *args, **kwargs): # 创建cls的对象时候调用
16 | with singleton_type.single_lock:
17 | if not hasattr(cls, "_instance"):
18 | cls._instance = super(singleton_type, cls).__call__(*args, **kwargs) # 创建cls的对象
19 |
20 | return cls._instance
21 |
--------------------------------------------------------------------------------
/instock/core/singleton_trade_date.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | # -*- coding: utf-8 -*-
3 |
4 | import logging
5 | import instock.core.stockfetch as stf
6 | from instock.lib.singleton_type import singleton_type
7 |
8 | __author__ = 'myh '
9 | __date__ = '2023/3/10 '
10 |
11 |
12 | # 读取股票交易日历数据
13 | class stock_trade_date(metaclass=singleton_type):
14 | def __init__(self):
15 | try:
16 | self.data = stf.fetch_stocks_trade_date()
17 | except Exception as e:
18 | logging.error(f"singleton.stock_trade_date处理异常:{e}")
19 |
20 | def get_data(self):
21 | return self.data
22 |
--------------------------------------------------------------------------------
/instock/web/templates/layout/indicators-main.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | InStock股票系统
7 |
13 | {% block meta %}{% end %}
14 |
15 |
16 |
17 | {% block main_content %}{% end %}
18 |
19 |
20 |
--------------------------------------------------------------------------------
/instock/web/templates/common/meta.html:
--------------------------------------------------------------------------------
1 | {% block meta %}
2 |
3 |
4 |
5 |
6 |
7 |
10 |
11 |
20 | {% end %}
--------------------------------------------------------------------------------
/docker/build.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | rm -rf stock
4 | rsync -av --progress ../../stock . --exclude .git --exclude .idea --exclude *.md --exclude *.bat --exclude __pycache__ --exclude .gitignore --exclude stock/cron --exclude stock/img --exclude stock/docker --exclude instock/cache --exclude instock/log --exclude instock/test
5 | rm -rf cron
6 | cp -r ../../stock/cron .
7 |
8 | DOCKER_NAME=mayanghua/instock
9 | TAG1=$(date "+%Y%m")
10 | TAG2=latest
11 |
12 | echo " docker build -f Dockerfile -t ${DOCKER_NAME} ."
13 | docker build -f Dockerfile -t ${DOCKER_NAME}:${TAG1} -t ${DOCKER_NAME}:${TAG2} .
14 | echo "#################################################################"
15 | echo " docker push ${DOCKER_NAME} "
16 |
17 | docker push ${DOCKER_NAME}:${TAG1}
18 | docker push ${DOCKER_NAME}:${TAG2}
--------------------------------------------------------------------------------
/instock/core/web_module_data.py:
--------------------------------------------------------------------------------
1 | #!/usr/local/bin/python
2 | # -*- coding: utf-8 -*-
3 |
4 |
5 | __author__ = 'myh '
6 | __date__ = '2023/5/11 '
7 |
8 |
9 | class web_module_data:
10 | def __init__(self, mode, type, ico, name, table_name, columns, column_names, primary_key, is_realtime, order_columns=None, order_by=None):
11 | self.mode = mode # 模式,query,editor 查询和编辑模式
12 | self.type = type
13 | self.ico = ico
14 | self.name = name
15 | self.table_name = table_name
16 | self.columns = columns
17 | self.column_names = column_names
18 | self.primary_key = primary_key
19 | self.is_realtime = is_realtime
20 | self.order_by = order_by
21 | self.order_columns = order_columns
22 | self.url = f"/instock/data?table_name={self.table_name}"
23 |
--------------------------------------------------------------------------------
/instock/web/base.py:
--------------------------------------------------------------------------------
1 | #!/usr/local/bin/python3
2 | # -*- coding: utf-8 -*-
3 |
4 | from abc import ABC
5 | import tornado.web
6 | import instock.core.singleton_stock_web_module_data as sswmd
7 |
8 | __author__ = 'myh '
9 | __date__ = '2023/3/10 '
10 |
11 |
12 | # 基础handler,主要负责检查mysql的数据库链接。
13 | class BaseHandler(tornado.web.RequestHandler, ABC):
14 | @property
15 | def db(self):
16 | try:
17 | # check every time。
18 | self.application.db.query("SELECT 1 ")
19 | except Exception as e:
20 | print(e)
21 | self.application.db.reconnect()
22 | return self.application.db
23 |
24 |
25 | class LeftMenu:
26 | def __init__(self, url):
27 | self.leftMenuList = sswmd.stock_web_module_data().get_data_list()
28 | self.current_url = url
29 |
30 |
31 | # 获得左菜单。
32 | def GetLeftMenu(url):
33 | return LeftMenu(url)
34 |
--------------------------------------------------------------------------------
/instock/bin/run_job.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | #export PYTHONPATH=/data/InStock
4 |
5 | #nohup &
6 | /usr/local/bin/python3 /data/InStock/instock/job/execute_daily_job.py
7 |
8 | echo ------整体作业 支持批量作业------
9 | echo 当前时间作业 python execute_daily_job.py
10 | echo 1个时间作业 python execute_daily_job.py 2023-03-01
11 | echo N个时间作业 python execute_daily_job.py 2023-03-01,2023-03-02
12 | echo 区间作业 python execute_daily_job.py 2023-03-01 2023-03-21
13 | echo ------单功能作业 除了创建数据库 其他都支持批量作业------
14 | echo 创建数据库作业 python init_job.py
15 | echo 综合选股作业 python selection_data_daily_job.py
16 | echo 基础数据实时作业 python basic_data_daily_job.py
17 | echo 基础数据收盘2小时后作业 python backtest_data_daily_job.py
18 | echo 基础数据非实时作业 python basic_data_other_daily_job.py
19 | echo 指标数据作业 python indicators_data_daily_job.py
20 | echo K线形态作业 klinepattern_data_daily_job.py
21 | echo 策略数据作业 python strategy_data_daily_job.py
22 | echo 回测数据 python backtest_data_daily_job.py
23 | echo ------正在执行作业中 请等待------
24 |
--------------------------------------------------------------------------------
/instock/core/strategy/turtle_trade.py:
--------------------------------------------------------------------------------
1 | #!/usr/local/bin/python
2 | # -*- coding: utf-8 -*-
3 |
4 |
5 | __author__ = 'myh '
6 | __date__ = '2023/3/10 '
7 |
8 | # 总市值
9 | BALANCE = 200000
10 |
11 | # 海龟交易法则
12 | # 最后一个交易日收市价为指定区间内最高价
13 | # 1.当日收盘价>=最近60日最高收盘价
14 | def check_enter(code_name, data, date=None, threshold=60):
15 | if date is None:
16 | end_date = code_name[0]
17 | else:
18 | end_date = date.strftime("%Y-%m-%d")
19 | if end_date is not None:
20 | mask = (data['date'] <= end_date)
21 | data = data.loc[mask]
22 | if len(data.index) < threshold:
23 | return False
24 |
25 | data = data.tail(n=threshold)
26 |
27 | max_price = 0
28 | for _close in data['close'].values:
29 | if _close > max_price:
30 | max_price = _close
31 |
32 | last_close = data.iloc[-1]['close']
33 |
34 | if last_close >= max_price:
35 | return True
36 |
37 | return False
38 |
--------------------------------------------------------------------------------
/instock/web/templates/layout/main.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | InStock股票系统
8 | {% block meta %}{% end %}
9 |
10 |
11 |
12 |
13 |
16 | {% block header %}{% end %}
17 | {% block left_menu %}{% end %}
18 |
19 |
20 | {% block main_content %}{% end %}
21 |
22 |
23 | {% block footer %}{% end %}
24 |
25 |
26 |
--------------------------------------------------------------------------------
/instock/trade/trade_service.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | # -*- coding: utf-8 -*-
3 |
4 | import os.path
5 | import sys
6 | # 在项目运行时,临时将项目路径添加到环境变量
7 | cpath_current = os.path.dirname(os.path.dirname(__file__))
8 | cpath = os.path.abspath(os.path.join(cpath_current, os.pardir))
9 | sys.path.append(cpath)
10 | need_data = os.path.join(cpath_current, 'config', 'trade_client.json')
11 | log_filepath = os.path.join(cpath_current, 'log', 'stock_trade.log')
12 | from instock.trade.robot.engine.main_engine import MainEngine
13 | from instock.trade.robot.infrastructure.default_handler import DefaultLogHandler
14 |
15 | __author__ = 'myh '
16 | __date__ = '2023/4/10 '
17 |
18 |
19 | def main():
20 | broker = 'gf_client'
21 | log_handler = DefaultLogHandler(name='交易服务', log_type='file', filepath=log_filepath)
22 | m = MainEngine(broker, need_data, log_handler)
23 | m.is_watch_strategy = True # 策略文件出现改动时,自动重载,不建议在生产环境下使用
24 | m.load_strategy()
25 | m.start()
26 |
27 |
28 | # main函数入口
29 | if __name__ == '__main__':
30 | main()
31 |
--------------------------------------------------------------------------------
/instock/trade/robot/infrastructure/strategy_template.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | # -*- coding: utf-8 -*-
3 |
4 |
5 | __author__ = 'myh '
6 | __date__ = '2023/4/10 '
7 |
8 |
9 | class StrategyTemplate:
10 | name = 'DefaultStrategyTemplate'
11 |
12 | def __init__(self, user, log_handler, main_engine):
13 | self.user = user
14 | self.main_engine = main_engine
15 | self.clock_engine = main_engine.clock_engine
16 | # 优先使用自定义 log 句柄, 否则使用主引擎日志句柄
17 | self.log = self.log_handler() or log_handler
18 | self.init()
19 |
20 | def init(self):
21 | # 进行相关的初始化操作
22 | pass
23 |
24 | def strategy(self):
25 | pass
26 |
27 | def clock(self, event):
28 | pass
29 |
30 | def log_handler(self):
31 | """
32 | 优先使用在此自定义 log 句柄, 否则返回None, 并使用主引擎日志句柄
33 | :return: log_handler or None
34 | """
35 | return None
36 |
37 | def shutdown(self):
38 | """
39 | 关闭进程前调用该函数
40 | :return:
41 | """
42 | pass
43 |
--------------------------------------------------------------------------------
/instock/web/templates/stock_indicators.html:
--------------------------------------------------------------------------------
1 | {% extends "layout/indicators.html" %}
2 | {% block main_content %}
3 |
4 |
5 |
25 | {% for element in comp_list %}
26 |
27 | {% raw element["div"] %}
28 | {% raw element["script"] %}
29 |
30 | {% end %}
31 | {% end %}
--------------------------------------------------------------------------------
/instock/core/strategy/keep_increasing.py:
--------------------------------------------------------------------------------
1 | #!/usr/local/bin/python
2 | # -*- coding: utf-8 -*-
3 |
4 | import numpy as np
5 | import talib as tl
6 |
7 | __author__ = 'myh '
8 | __date__ = '2023/3/10 '
9 |
10 |
11 | # 持续上涨(MA30向上)
12 | # 均线多头
13 | # 1.30日前的30日均线<20日前的30日均线<10日前的30日均线<当日的30日均线
14 | # 3.(当日的30日均线/30日前的30日均线)>1.2
15 | def check(code_name, data, date=None, threshold=30):
16 | if date is None:
17 | end_date = code_name[0]
18 | else:
19 | end_date = date.strftime("%Y-%m-%d")
20 | if end_date is not None:
21 | mask = (data['date'] <= end_date)
22 | data = data.loc[mask].copy()
23 | if len(data.index) < threshold:
24 | return False
25 |
26 | data.loc[:, 'ma30'] = tl.MA(data['close'].values, timeperiod=30)
27 | data['ma30'].values[np.isnan(data['ma30'].values)] = 0.0
28 |
29 | data = data.tail(n=threshold)
30 |
31 | step1 = round(threshold / 3)
32 | step2 = round(threshold * 2 / 3)
33 |
34 | if data.iloc[0]['ma30'] < data.iloc[step1]['ma30'] < \
35 | data.iloc[step2]['ma30'] < data.iloc[-1]['ma30'] and data.iloc[-1]['ma30'] > 1.2 * data.iloc[0]['ma30']:
36 | return True
37 | else:
38 | return False
39 |
--------------------------------------------------------------------------------
/instock/trade/robot/infrastructure/strategy_wrapper.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | # -*- coding: utf-8 -*-
3 |
4 |
5 | import multiprocessing as mp
6 | from threading import Thread
7 |
8 | __author__ = 'myh '
9 | __date__ = '2023/4/10 '
10 |
11 |
12 | class ProcessWrapper(object):
13 | def __init__(self, strategy):
14 | self.__strategy = strategy
15 | # 时钟队列
16 | self.__clock_queue = mp.Queue(10000)
17 | # 包装进程
18 | self.__proc = mp.Process(target=self._process)
19 | self.__proc.start()
20 |
21 | def stop(self):
22 | self.__clock_queue.put(0)
23 | self.__proc.join()
24 |
25 | def on_clock(self, event):
26 | self.__clock_queue.put(event)
27 |
28 | def _process_clock(self):
29 | while True:
30 |
31 | try:
32 | event = self.__clock_queue.get(block=True)
33 | # 退出
34 | if event == 0:
35 | break
36 | self.__strategy.clock(event)
37 | except:
38 | pass
39 |
40 | def _process(self):
41 | clock_thread = Thread(target=self._process_clock, name="ProcessWrapper._process_clock")
42 | clock_thread.start()
43 |
44 | clock_thread.join()
45 |
--------------------------------------------------------------------------------
/instock/bin/run_job.bat:
--------------------------------------------------------------------------------
1 | chcp 65001
2 | @echo off
3 | cd %~dp0
4 | cd ..
5 | cd job
6 | echo ------整体作业,支持批量作业------
7 | echo 当前时间作业 python execute_daily_job.py
8 | echo 1个时间作业 python execute_daily_job.py 2023-03-01
9 | echo N个时间作业 python execute_daily_job.py 2023-03-01,2023-03-02
10 | echo 区间作业 python execute_daily_job.py 2023-03-01 2023-03-21
11 | echo ------单功能作业,除了创建数据库,其他都支持批量作业------
12 | echo 创建数据库作业 python init_job.py
13 | echo 综合选股作业 python selection_data_daily_job.py
14 | echo 基础数据实时作业 python basic_data_daily_job.py
15 | echo 基础数据收盘2小时后作业 python backtest_data_daily_job.py
16 | echo 基础数据非实时作业 python basic_data_other_daily_job.py
17 | echo 指标数据作业 python indicators_data_daily_job.py
18 | echo K线形态作业 klinepattern_data_daily_job.py
19 | echo 策略数据作业 python strategy_data_daily_job.py
20 | echo 回测数据 python backtest_data_daily_job.py
21 | echo ------正在执行作业中,请等待------
22 | :: python execute_daily_job.py 2022-01-24,2022-02-25,2022-03-24,2022-04-18,2022-05-18,2022-06-06,2022-07-21,2022-08-26,2022-09-16,2022-10-28,2022-11-04,2022-12-16
23 | ::python execute_daily_job.py 2022-01-10,2022-02-14,2022-03-14,2022-04-11,2022-05-10,2022-06-13,2022-07-04,2022-08-08,2022-09-05,2022-10-11,2022-11-14,2022-12-05
24 | :: python execute_daily_job.py 2022-05-18 2022-05-25
25 | python execute_daily_job.py
26 | pause
27 | exit
28 |
--------------------------------------------------------------------------------
/instock/trade/robot/infrastructure/default_handler.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | # -*- coding: utf-8 -*-
3 |
4 | import os
5 | import sys
6 | import logbook
7 | from logbook import Logger, StreamHandler, FileHandler
8 |
9 | __author__ = 'myh '
10 | __date__ = '2023/4/10 '
11 |
12 | logbook.set_datetime_format('local')
13 |
14 |
15 | class DefaultLogHandler(object):
16 | """默认的 Log 类"""
17 |
18 | def __init__(self, name='default', log_type='stdout', filepath='default.log', loglevel='DEBUG'):
19 | """Log对象
20 | :param name: log 名字
21 | :param :logtype: 'stdout' 输出到屏幕, 'file' 输出到指定文件
22 | :param :filename: log 文件名
23 | :param :loglevel: 设定log等级 ['CRITICAL', 'ERROR', 'WARNING', 'NOTICE', 'INFO', 'DEBUG', 'TRACE', 'NOTSET']
24 | :return log handler object
25 | """
26 | self.log = Logger(name)
27 | if log_type == 'stdout':
28 | StreamHandler(sys.stdout, level=loglevel).push_application()
29 | if log_type == 'file':
30 | if os.path.isdir(filepath) and not os.path.exists(filepath):
31 | os.makedirs(os.path.dirname(filepath))
32 | file_handler = FileHandler(filepath, level=loglevel)
33 | self.log.handlers.append(file_handler)
34 |
35 | def __getattr__(self, item, *args, **kwargs):
36 | return self.log.__getattribute__(item, *args, **kwargs)
37 |
--------------------------------------------------------------------------------
/instock/core/strategy/high_tight_flag.py:
--------------------------------------------------------------------------------
1 | #!/usr/local/bin/python
2 | # -*- coding: utf-8 -*-
3 |
4 |
5 | __author__ = 'myh '
6 | __date__ = '2023/3/10 '
7 |
8 |
9 | # 高而窄的旗形
10 | # 1.必须至少上市交易60日
11 | # 2.当日收盘价/之前24~10日的最低价>=1.9
12 | # 3.之前24~10日必须连续两天涨幅大于等于9.5%
13 | def check_high_tight(code_name, data, date=None, threshold=60, istop=False):
14 | # 龙虎榜上必须有机构
15 | if not istop:
16 | return False
17 | if date is None:
18 | end_date = code_name[0]
19 | else:
20 | end_date = date.strftime("%Y-%m-%d")
21 | if end_date is not None:
22 | mask = (data['date'] <= end_date)
23 | data = data.loc[mask]
24 | if len(data.index) < threshold:
25 | return False
26 |
27 | data = data.tail(n=threshold)
28 |
29 | data = data.tail(n=24)
30 | data = data.head(n=14)
31 | low = data['low'].values.min()
32 | ratio_increase = data.iloc[-1]['high'] / low
33 | if ratio_increase < 1.9:
34 | return False
35 |
36 | # 连续两天涨幅大于等于10%
37 | previous_p_change = 0.0
38 | for _p_change in data['p_change'].values:
39 | # 单日跌幅超7%;高开低走7%;两日累计跌幅10%;两日高开低走累计10%
40 | if _p_change >= 9.5:
41 | if previous_p_change >= 9.5:
42 | return True
43 | else:
44 | previous_p_change = _p_change
45 | else:
46 | previous_p_change = 0.0
47 |
48 | return False
49 |
--------------------------------------------------------------------------------
/instock/core/strategy/low_backtrace_increase.py:
--------------------------------------------------------------------------------
1 | #!/usr/local/bin/python
2 | # -*- coding: utf-8 -*-
3 |
4 |
5 | __author__ = 'myh '
6 | __date__ = '2023/3/10 '
7 |
8 |
9 | # 无大幅回撤
10 | # 1.当日收盘价比60日前的收盘价的涨幅小于0.6
11 | # 2.最近60日,不能有单日跌幅超7%、高开低走7%、两日累计跌幅10%、两日高开低走累计10%
12 | def check(code_name, data, date=None, threshold=60):
13 | if date is None:
14 | end_date = code_name[0]
15 | else:
16 | end_date = date.strftime("%Y-%m-%d")
17 | if end_date is not None:
18 | mask = (data['date'] <= end_date)
19 | data = data.loc[mask]
20 | if len(data.index) < threshold:
21 | return False
22 |
23 | data = data.tail(n=threshold)
24 |
25 | ratio_increase = (data.iloc[-1]['close'] - data.iloc[0]['close']) / data.iloc[0]['close']
26 | if ratio_increase < 0.6:
27 | return False
28 |
29 | # 允许有一次“洗盘”
30 | previous_p_change = 100.0
31 | previous_open = -1000000.0
32 | for _p_change, _close, _open in zip(data['p_change'].values, data['close'].values, data['open'].values):
33 | # 单日跌幅超7%;高开低走7%;两日累计跌幅10%;两日高开低走累计10%
34 | if _p_change < -7 or (_close - _open) / _open * 100 < -7 \
35 | or previous_p_change + _p_change < -10 \
36 | or (_close - previous_open)/previous_open * 100 < -10:
37 | return False
38 | previous_p_change = _p_change
39 | previous_open = _open
40 | return True
41 |
--------------------------------------------------------------------------------
/instock/core/strategy/climax_limitdown.py:
--------------------------------------------------------------------------------
1 | #!/usr/local/bin/python
2 | # -*- coding: utf-8 -*-
3 |
4 |
5 | import numpy as np
6 | import talib as tl
7 |
8 | __author__ = 'myh '
9 | __date__ = '2023/3/10 '
10 |
11 | # 放量跌停
12 | # 1.跌>9.5%
13 | # 2.成交额不低于2亿
14 | # 3.成交量至少是5日平均成交量的4倍
15 | def check(code_name, data, date=None, threshold=60):
16 | if date is None:
17 | end_date = code_name[0]
18 | else:
19 | end_date = date.strftime("%Y-%m-%d")
20 | if end_date is not None:
21 | mask = (data['date'] <= end_date)
22 | data = data.loc[mask].copy()
23 | if len(data.index) < threshold:
24 | return False
25 |
26 | p_change = data.iloc[-1]['p_change']
27 | if p_change > -9.5:
28 | return False
29 |
30 | data.loc[:, 'vol_ma5'] = tl.MA(data['volume'].values, timeperiod=5)
31 | data['vol_ma5'].values[np.isnan(data['vol_ma5'].values)] = 0.0
32 |
33 | data = data.tail(n=threshold + 1)
34 | if len(data.index) < threshold + 1:
35 | return False
36 |
37 | # 最后一天收盘价
38 | last_close = data.iloc[-1]['close']
39 | # 最后一天成交量
40 | last_vol = data.iloc[-1]['volume']
41 |
42 | amount = last_close * last_vol
43 |
44 | # 成交额不低于2亿
45 | if amount < 200000000:
46 | return False
47 |
48 | data = data.head(n=threshold)
49 |
50 | mean_vol = data.iloc[-1]['vol_ma5']
51 |
52 | vol_ratio = last_vol / mean_vol
53 | if vol_ratio >= 4:
54 | return True
55 | else:
56 | return False
57 |
--------------------------------------------------------------------------------
/instock/job/basic_data_after_close_daily_job.py:
--------------------------------------------------------------------------------
1 | #!/usr/local/bin/python3
2 | # -*- coding: utf-8 -*-
3 |
4 | import logging
5 | import os.path
6 | import sys
7 |
8 | cpath_current = os.path.dirname(os.path.dirname(__file__))
9 | cpath = os.path.abspath(os.path.join(cpath_current, os.pardir))
10 | sys.path.append(cpath)
11 | import instock.lib.run_template as runt
12 | import instock.core.tablestructure as tbs
13 | import instock.lib.database as mdb
14 | import instock.core.stockfetch as stf
15 |
16 | __author__ = 'myh '
17 | __date__ = '2023/3/10 '
18 |
19 |
20 | # 每日股票大宗交易
21 | def save_after_close_stock_blocktrade_data(date):
22 | try:
23 | data = stf.fetch_stock_blocktrade_data(date)
24 | if data is None or len(data.index) == 0:
25 | return
26 |
27 | table_name = tbs.TABLE_CN_STOCK_BLOCKTRADE['name']
28 | # 删除老数据。
29 | if mdb.checkTableIsExist(table_name):
30 | del_sql = f"DELETE FROM `{table_name}` where `date` = '{date}'"
31 | mdb.executeSql(del_sql)
32 | cols_type = None
33 | else:
34 | cols_type = tbs.get_field_types(tbs.TABLE_CN_STOCK_BLOCKTRADE['columns'])
35 |
36 | mdb.insert_db_from_df(data, table_name, cols_type, False, "`date`,`code`")
37 | except Exception as e:
38 | logging.error(f"basic_data_other_daily_job.save_stock_blocktrade_data处理异常:{e}")
39 |
40 |
41 | def main():
42 | runt.run_with_args(save_after_close_stock_blocktrade_data)
43 |
44 |
45 | # main函数入口
46 | if __name__ == '__main__':
47 | main()
48 |
--------------------------------------------------------------------------------
/instock/core/strategy/enter.py:
--------------------------------------------------------------------------------
1 | #!/usr/local/bin/python
2 | # -*- coding: utf-8 -*-
3 |
4 | import numpy as np
5 | import talib as tl
6 |
7 |
8 | __author__ = 'myh '
9 | __date__ = '2023/3/10 '
10 |
11 |
12 | # 放量上涨
13 | # 1.当日比前一天上涨小于2%或收盘价小于开盘价
14 | # 2.当日成交额不低于2亿
15 | # 3.当日成交量/5日平均成交量>=2
16 | def check_volume(code_name, data, date=None, threshold=60):
17 | if date is None:
18 | end_date = code_name[0]
19 | else:
20 | end_date = date.strftime("%Y-%m-%d")
21 | if end_date is not None:
22 | mask = (data['date'] <= end_date)
23 | data = data.loc[mask].copy()
24 | if len(data.index) < threshold:
25 | return False
26 |
27 | p_change = data.iloc[-1]['p_change']
28 | if p_change < 2 or data.iloc[-1]['close'] < data.iloc[-1]['open']:
29 | return False
30 |
31 | data.loc[:, 'vol_ma5'] = tl.MA(data['volume'].values, timeperiod=5)
32 | data['vol_ma5'].values[np.isnan(data['vol_ma5'].values)] = 0.0
33 |
34 | data = data.tail(n=threshold + 1)
35 | if len(data) < threshold + 1:
36 | return False
37 |
38 | # 最后一天收盘价
39 | last_close = data.iloc[-1]['close']
40 | # 最后一天成交量
41 | last_vol = data.iloc[-1]['volume']
42 |
43 | amount = last_close * last_vol
44 |
45 | # 成交额不低于2亿
46 | if amount < 200000000:
47 | return False
48 |
49 | data = data.head(n=threshold)
50 |
51 | mean_vol = data.iloc[-1]['vol_ma5']
52 |
53 | vol_ratio = last_vol / mean_vol
54 | if vol_ratio >= 2:
55 | return True
56 | else:
57 | return False
58 |
--------------------------------------------------------------------------------
/instock/core/backtest/rate_stats.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | # -*- coding: utf-8 -*-
3 |
4 | import logging
5 | import numpy as np
6 | import pandas as pd
7 |
8 | __author__ = 'myh '
9 | __date__ = '2023/3/10 '
10 |
11 |
12 | def get_rates(code_name, data, stock_column, threshold=101):
13 | try:
14 | # 增加空判断,如果是空返回 0 数据。
15 | if data is None:
16 | return None
17 |
18 | start_date = code_name[0]
19 | code = code_name[1]
20 | # 设置返回数组。
21 | stock_data_list = [start_date, code]
22 |
23 | mask = (data['date'] >= start_date)
24 | data = data.loc[mask].copy()
25 | data = data.head(n=threshold)
26 |
27 | if len(data.index) <= 1:
28 | return None
29 |
30 | close1 = data.iloc[0]['close']
31 | # data.loc[:, 'sum_pct_change'] = data['close'].apply(lambda x: round(100 * (x - close1) / close1, 2))
32 | data.loc[:, 'sum_pct_change'] = np.around(100 * (data['close'].values - close1) / close1, decimals=2)
33 | # 计算区间最高、最低价格
34 |
35 | first = True
36 | col_len = len(data.columns)
37 | for row in data.values:
38 | if first:
39 | first = False
40 | else:
41 | stock_data_list.append(row[col_len-1])
42 |
43 | _l = len(stock_column) - len(stock_data_list)
44 | for i in range(0, _l):
45 | stock_data_list.append(None)
46 |
47 | except Exception as e:
48 | logging.error(f"rate_stats.get_rates处理异常:{code}代码{e}")
49 |
50 | return pd.Series(stock_data_list, index=stock_column)
51 |
--------------------------------------------------------------------------------
/instock/job/selection_data_daily_job.py:
--------------------------------------------------------------------------------
1 | #!/usr/local/bin/python3
2 | # -*- coding: utf-8 -*-
3 |
4 |
5 | import logging
6 | import pandas as pd
7 | import os.path
8 | import sys
9 |
10 | cpath_current = os.path.dirname(os.path.dirname(__file__))
11 | cpath = os.path.abspath(os.path.join(cpath_current, os.pardir))
12 | sys.path.append(cpath)
13 | import instock.lib.run_template as runt
14 | import instock.core.tablestructure as tbs
15 | import instock.lib.database as mdb
16 | import instock.core.stockfetch as stf
17 |
18 | __author__ = 'myh '
19 | __date__ = '2023/5/5 '
20 |
21 |
22 | def save_nph_stock_selection_data(date, before=True):
23 | if before:
24 | return
25 |
26 | try:
27 | data = stf.fetch_stock_selection()
28 | if data is None:
29 | return
30 |
31 | table_name = tbs.TABLE_CN_STOCK_SELECTION['name']
32 | # 删除老数据。
33 | if mdb.checkTableIsExist(table_name):
34 | _date = data.iloc[0]['date']
35 | del_sql = f"DELETE FROM `{table_name}` where `date` = '{_date}'"
36 | mdb.executeSql(del_sql)
37 | cols_type = None
38 | else:
39 | cols_type = tbs.get_field_types(tbs.TABLE_CN_STOCK_SELECTION['columns'])
40 |
41 | mdb.insert_db_from_df(data, table_name, cols_type, False, "`date`,`code`")
42 | except Exception as e:
43 | logging.error(f"selection_data_daily_job.save_nph_stock_selection_data处理异常:{e}")
44 |
45 |
46 | def main():
47 | runt.run_with_args(save_nph_stock_selection_data)
48 |
49 |
50 | # main函数入口
51 | if __name__ == '__main__':
52 | main()
53 |
--------------------------------------------------------------------------------
/supervisor/supervisord.conf:
--------------------------------------------------------------------------------
1 | [unix_http_server]
2 | file=/tmp/supervisor.sock ; the path to the socket file
3 |
4 | [inet_http_server] ; inet (TCP) server disabled by default
5 | port=*:9001 ; ip_address:port specifier, *:port for all iface
6 | ;username=user ; default is no username (open server)
7 | ;password=123 ; default is no password (open server)
8 |
9 | [supervisord]
10 | logfile=/tmp/supervisord.log ; main log file; default $CWD/supervisord.log
11 | logfile_maxbytes=50MB ; max main logfile bytes b4 rotation; default 50MB
12 | logfile_backups=10 ; # of main logfile backups; 0 means none, default 10
13 | loglevel=info ; log level; default info; others: debug,warn,trace
14 | pidfile=/tmp/supervisord.pid ; supervisord pidfile; default supervisord.pid
15 | nodaemon=false ; start in foreground if true; default false
16 | minfds=1024 ; min. avail startup file descriptors; default 1024
17 | minprocs=200 ; min. avail process descriptors;default 200
18 |
19 | [rpcinterface:supervisor]
20 | supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface
21 |
22 | [supervisorctl]
23 | serverurl=unix:///tmp/supervisor.sock ; use a unix:// URL for a unix socket
24 |
25 | [program:run_job]
26 | command=/data/InStock/instock/bin/run_job.sh
27 | autorestart=false
28 | startretries=0
29 | priority=100
30 |
31 | [program:run_web]
32 | command=/data/InStock/instock/bin/run_web.sh
33 | autorestart=true
34 | priority=500
35 | stopasgroup=true
36 | killasgroup=true
37 |
38 | [program:run_cron]
39 | command=/data/InStock/instock/bin/run_cron.sh
40 | autorestart=true
41 | priority=900
42 |
--------------------------------------------------------------------------------
/instock/core/strategy/breakthrough_platform.py:
--------------------------------------------------------------------------------
1 | #!/usr/local/bin/python
2 | # -*- coding: utf-8 -*-
3 |
4 | from datetime import datetime
5 | import numpy as np
6 | import talib as tl
7 | from instock.core.strategy import enter
8 |
9 | __author__ = 'myh '
10 | __date__ = '2023/3/10 '
11 |
12 |
13 | # 平台突破策略
14 | # 1.60日内某日收盘价>=60日均线>开盘价
15 | # 2.且【1】放量上涨
16 | # 3.且【1】间之前时间,任意一天收盘价与60日均线偏离在-5%~20%之间。
17 | def check(code_name, data, date=None, threshold=60):
18 | origin_data = data
19 | if date is None:
20 | end_date = code_name[0]
21 | else:
22 | end_date = date.strftime("%Y-%m-%d")
23 | if end_date is not None:
24 | mask = (data['date'] <= end_date)
25 | data = data.loc[mask].copy()
26 | if len(data.index) < threshold:
27 | return False
28 |
29 | data.loc[:, 'ma60'] = tl.MA(data['close'].values, timeperiod=60)
30 | data['ma60'].values[np.isnan(data['ma60'].values)] = 0.0
31 |
32 | data = data.tail(n=threshold)
33 |
34 | breakthrough_row = None
35 | for _close, _open, _date, _ma60 in zip(data['close'].values, data['open'].values, data['date'].values, data['ma60'].values):
36 | if _open < _ma60 <= _close:
37 | if enter.check_volume(code_name, origin_data, date=datetime.date(datetime.strptime(_date, '%Y-%m-%d')), threshold=threshold):
38 | breakthrough_row = _date
39 | break
40 |
41 | if breakthrough_row is None:
42 | return False
43 |
44 | data_front = data.loc[(data['date'] < breakthrough_row) & (data['ma60'] > 0)]
45 | for _close, _ma60 in zip(data_front['close'].values, data_front['ma60'].values):
46 | if not (-0.05 < ((_ma60 - _close) / _ma60) < 0.2):
47 | return False
48 |
49 | return True
50 |
--------------------------------------------------------------------------------
/instock/core/strategy/low_atr.py:
--------------------------------------------------------------------------------
1 | #!/usr/local/bin/python
2 | # -*- coding: utf-8 -*-
3 |
4 |
5 | __author__ = 'myh '
6 | __date__ = '2023/3/10 '
7 |
8 |
9 | # 低ATR成长
10 | # 1.必须至少上市交易250日
11 | # 2.最近10个交易日的最高收盘价必须比最近10个交易日的最低收盘价高1.1倍
12 | def check_low_increase(code_name, data, date=None, ma_short=30, ma_long=250, threshold=10):
13 | if date is None:
14 | end_date = code_name[0]
15 | else:
16 | end_date = date.strftime("%Y-%m-%d")
17 | if end_date is not None:
18 | mask = (data['date'] <= end_date)
19 | data = data.loc[mask]
20 | if len(data.index) < ma_long:
21 | return False
22 |
23 | # data.loc[:, 'ma_short'] = tl.MA(data['close'].values, timeperiod=ma_short)
24 | # data['ma_short'].values[np.isnan(data['ma_short'].values)] = 0.0
25 | # data.loc[:, 'ma_long'] = tl.MA(data['close'].values, timeperiod=ma_long)
26 | # data['ma_long'].values[np.isnan(data['ma_long'].values)] = 0.0
27 |
28 | data = data.tail(n=threshold)
29 | inc_days = 0
30 | dec_days = 0
31 | days_count = len(data.index)
32 | if days_count < threshold:
33 | return False
34 |
35 | # 区间最低点
36 | lowest_row = 1000000
37 | # 区间最高点
38 | highest_row = 0
39 |
40 | total_change = 0.0
41 | for _close, _p_change in zip(data['close'].values, data['p_change'].values):
42 | if _p_change > 0:
43 | total_change += abs(_p_change)
44 | inc_days = inc_days + 1
45 | elif _p_change < 0:
46 | total_change += abs(_p_change)
47 | dec_days = dec_days + 1
48 |
49 | if _close > highest_row:
50 | highest_row = _close
51 | elif _close < lowest_row:
52 | lowest_row = _close
53 |
54 | atr = total_change / days_count
55 | if atr > 10:
56 | return False
57 |
58 | ratio = (highest_row - lowest_row) / lowest_row
59 |
60 | if ratio > 1.1:
61 | return True
62 |
63 | return False
64 |
--------------------------------------------------------------------------------
/instock/trade/strategies/stagging.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | # -*- coding: utf-8 -*-
3 |
4 | import os.path
5 | import datetime as dt
6 | from dateutil import tz
7 | from instock.trade.robot.infrastructure.default_handler import DefaultLogHandler
8 | from instock.trade.robot.infrastructure.strategy_template import StrategyTemplate
9 |
10 | __author__ = 'myh '
11 | __date__ = '2023/4/10 '
12 |
13 |
14 | class Strategy(StrategyTemplate):
15 | name = 'stagging'
16 |
17 | def init(self):
18 | # 通过下面的方式来获取时间戳
19 | # now_dt = self.clock_engine.now_dt
20 | # now = self.clock_engine.now
21 | # now = time.time()
22 |
23 | # 注册时钟事件
24 | clock_type = self.name
25 | moment = dt.time(10, 0, 0, tzinfo=tz.tzlocal())
26 | self.clock_engine.register_moment(clock_type, moment)
27 |
28 | # 注册时钟间隔事件, 不在交易阶段也会触发, clock_type == minute_interval
29 | minute_interval = 1.5
30 | self.clock_engine.register_interval(minute_interval, trading=False)
31 |
32 | def strategy(self):
33 | self.log.info('打新股')
34 | self.user.auto_ipo()
35 |
36 | def clock(self, event):
37 | """在交易时间会定时推送 clock 事件
38 | :param event: event.data.clock_event 为 [0.5, 1, 3, 5, 15, 30, 60] 单位为分钟, ['open', 'close'] 为开市、收市
39 | event.data.trading_state bool 是否处于交易时间
40 | """
41 | if event.data.clock_event == self.name:
42 | self.strategy()
43 |
44 | def log_handler(self):
45 | """自定义 log 记录方式"""
46 | cpath_current = os.path.dirname(os.path.dirname(__file__))
47 | cpath = os.path.abspath(os.path.join(cpath_current, os.pardir))
48 | log_filepath = os.path.join(cpath, 'log', f'{self.name}.log')
49 | return DefaultLogHandler(self.name, log_type='file', filepath=log_filepath)
50 |
51 | def shutdown(self):
52 | """
53 | 关闭进程前的调用
54 | :return:
55 | """
56 | self.log.info("假装在关闭前保存了策略数据")
57 |
--------------------------------------------------------------------------------
/instock/job/execute_daily_job.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | # -*- coding: utf-8 -*-
3 |
4 |
5 | import time
6 | import datetime
7 | import concurrent.futures
8 | import logging
9 | import os.path
10 | import sys
11 |
12 | # 在项目运行时,临时将项目路径添加到环境变量
13 | cpath_current = os.path.dirname(os.path.dirname(__file__))
14 | cpath = os.path.abspath(os.path.join(cpath_current, os.pardir))
15 | sys.path.append(cpath)
16 | log_path = os.path.join(cpath_current, 'log')
17 | if not os.path.exists(log_path):
18 | os.makedirs(log_path)
19 | logging.basicConfig(format='%(asctime)s %(message)s', filename=os.path.join(log_path, 'stock_execute_job.log'))
20 | logging.getLogger().setLevel(logging.INFO)
21 | import init_job as bj
22 | import basic_data_daily_job as hdj
23 | import basic_data_other_daily_job as hdtj
24 | import basic_data_after_close_daily_job as acdj
25 | import indicators_data_daily_job as gdj
26 | import strategy_data_daily_job as sdj
27 | import backtest_data_daily_job as bdj
28 | import klinepattern_data_daily_job as kdj
29 | import selection_data_daily_job as sddj
30 |
31 | __author__ = 'myh '
32 | __date__ = '2023/3/10 '
33 |
34 |
35 | def main():
36 | start = time.time()
37 | _start = datetime.datetime.now()
38 | logging.info("######## 任务执行时间: %s #######" % _start.strftime("%Y-%m-%d %H:%M:%S.%f"))
39 | # 第1步创建数据库
40 | bj.main()
41 | # 第2.1步创建股票基础数据表
42 | hdj.main()
43 | # 第2.2步创建综合股票数据表
44 | sddj.main()
45 | with concurrent.futures.ThreadPoolExecutor() as executor:
46 | # # 第3.1步创建股票其它基础数据表
47 | executor.submit(hdtj.main)
48 | # # 第3.2步创建股票指标数据表
49 | executor.submit(gdj.main)
50 | # # # # 第4步创建股票k线形态表
51 | executor.submit(kdj.main)
52 | # # # # 第5步创建股票策略数据表
53 | executor.submit(sdj.main)
54 |
55 | # # # # 第6步创建股票回测
56 | bdj.main()
57 |
58 | # # # # 第7步创建股票闭盘后才有的数据
59 | acdj.main()
60 |
61 | logging.info("######## 完成任务, 使用时间: %s 秒 #######" % (time.time() - start))
62 |
63 |
64 | # main函数入口
65 | if __name__ == '__main__':
66 | main()
67 |
--------------------------------------------------------------------------------
/instock/core/pattern/pattern_recognitions.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | # -*- coding: utf-8 -*-
3 |
4 | import logging
5 |
6 | __author__ = 'myh '
7 | __date__ = '2023/3/24 '
8 |
9 |
10 | def get_pattern_recognitions(data, stock_column, end_date=None, threshold=120, calc_threshold=None):
11 | isCopy = False
12 | if end_date is not None:
13 | mask = (data['date'] <= end_date)
14 | data = data.loc[mask]
15 | isCopy = True
16 | if calc_threshold is not None:
17 | data = data.tail(n=calc_threshold)
18 | isCopy = True
19 | if isCopy:
20 | data = data.copy()
21 |
22 | for k in stock_column:
23 | try:
24 | data.loc[:, k] = stock_column[k]['func'](data['open'].values, data['high'].values, data['low'].values, data['close'].values)
25 | except Exception as e:
26 | pass
27 |
28 | if data is None or len(data.index) == 0:
29 | return None
30 |
31 | if threshold is not None:
32 | data = data.tail(n=threshold).copy()
33 |
34 | return data
35 |
36 |
37 | def get_pattern_recognition(code_name, data, stock_column, date=None, calc_threshold=12):
38 | try:
39 | # 增加空判断,如果是空返回 0 数据。
40 | if date is None:
41 | end_date = code_name[0]
42 | else:
43 | end_date = date.strftime("%Y-%m-%d")
44 |
45 | code = code_name[1]
46 | # 设置返回数组。
47 | # 增加空判断,如果是空返回 0 数据。
48 | if len(data.index) <= 1:
49 | return None
50 |
51 | stockStat = get_pattern_recognitions(data, stock_column, end_date=end_date, threshold=1,
52 | calc_threshold=calc_threshold)
53 |
54 | if stockStat is None:
55 | return None
56 |
57 | isHas = False
58 | for k in stock_column:
59 | if stockStat.iloc[0][k] != 0:
60 | isHas = True
61 | break
62 |
63 | if isHas:
64 | stockStat.loc[:, 'code'] = code
65 | return stockStat.iloc[0, -(len(stock_column) + 1):]
66 |
67 | except Exception as e:
68 | logging.error(f"pattern_recognitions.get_pattern_recognition处理异常:{code}代码{e}")
69 |
70 | return None
71 |
--------------------------------------------------------------------------------
/instock/job/init_job.py:
--------------------------------------------------------------------------------
1 | #!/usr/local/bin/python3
2 | # -*- coding: utf-8 -*-
3 |
4 |
5 | import logging
6 | import pymysql
7 | import os.path
8 | import sys
9 |
10 | cpath_current = os.path.dirname(os.path.dirname(__file__))
11 | cpath = os.path.abspath(os.path.join(cpath_current, os.pardir))
12 | sys.path.append(cpath)
13 | import instock.lib.database as mdb
14 |
15 | __author__ = 'myh '
16 | __date__ = '2023/3/10 '
17 |
18 |
19 | # 创建新数据库。
20 | def create_new_database():
21 | _MYSQL_CONN_DBAPI = mdb.MYSQL_CONN_DBAPI.copy()
22 | _MYSQL_CONN_DBAPI['database'] = "mysql"
23 | with pymysql.connect(**_MYSQL_CONN_DBAPI) as conn:
24 | with conn.cursor() as db:
25 | try:
26 | create_sql = f"CREATE DATABASE IF NOT EXISTS `{mdb.db_database}` CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci"
27 | db.execute(create_sql)
28 | create_new_base_table()
29 | except Exception as e:
30 | logging.error(f"init_job.create_new_database处理异常:{e}")
31 |
32 |
33 | # 创建基础表。
34 | def create_new_base_table():
35 | with pymysql.connect(**mdb.MYSQL_CONN_DBAPI) as conn:
36 | with conn.cursor() as db:
37 | create_table_sql = """CREATE TABLE IF NOT EXISTS `cn_stock_attention` (
38 | `datetime` datetime(0) NULL DEFAULT NULL,
39 | `code` varchar(6) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
40 | PRIMARY KEY (`code`) USING BTREE,
41 | INDEX `INIX_DATETIME`(`datetime`) USING BTREE
42 | ) CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;"""
43 | db.execute(create_table_sql)
44 |
45 |
46 | def check_database():
47 | with pymysql.connect(**mdb.MYSQL_CONN_DBAPI) as conn:
48 | with conn.cursor() as db:
49 | db.execute(" select 1 ")
50 |
51 |
52 | def main():
53 | # 检查,如果执行 select 1 失败,说明数据库不存在,然后创建一个新的数据库。
54 | try:
55 | check_database()
56 | except Exception as e:
57 | logging.error("执行信息:数据库不存在,将创建。")
58 | # 检查数据库失败,
59 | create_new_database()
60 | # 执行数据初始化。
61 |
62 |
63 | # main函数入口
64 | if __name__ == '__main__':
65 | main()
66 |
--------------------------------------------------------------------------------
/instock/core/singleton_stock.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | # -*- coding: utf-8 -*-
3 |
4 | import logging
5 | import concurrent.futures
6 | import instock.core.stockfetch as stf
7 | import instock.core.tablestructure as tbs
8 | import instock.lib.trade_time as trd
9 | from instock.lib.singleton_type import singleton_type
10 |
11 | __author__ = 'myh '
12 | __date__ = '2023/3/10 '
13 |
14 |
15 | # 读取当天股票数据
16 | class stock_data(metaclass=singleton_type):
17 | def __init__(self, date):
18 | try:
19 | self.data = stf.fetch_stocks(date)
20 | except Exception as e:
21 | logging.error(f"singleton.stock_data处理异常:{e}")
22 |
23 | def get_data(self):
24 | return self.data
25 |
26 |
27 | # 读取股票历史数据
28 | class stock_hist_data(metaclass=singleton_type):
29 | def __init__(self, date=None, stocks=None, workers=16):
30 | if stocks is None:
31 | _subset = stock_data(date).get_data()[list(tbs.TABLE_CN_STOCK_FOREIGN_KEY['columns'])]
32 | stocks = [tuple(x) for x in _subset.values]
33 | if stocks is None:
34 | self.data = None
35 | return
36 | date_start, is_cache = trd.get_trade_hist_interval(stocks[0][0]) # 提高运行效率,只运行一次
37 | _data = {}
38 | try:
39 | # max_workers是None还是没有给出,将默认为机器cup个数*5
40 | with concurrent.futures.ThreadPoolExecutor(max_workers=workers) as executor:
41 | future_to_stock = {executor.submit(stf.fetch_stock_hist, stock, date_start, is_cache): stock for stock
42 | in stocks}
43 | for future in concurrent.futures.as_completed(future_to_stock):
44 | stock = future_to_stock[future]
45 | try:
46 | __data = future.result()
47 | if __data is not None:
48 | _data[stock] = __data
49 | except Exception as e:
50 | logging.error(f"singleton.stock_hist_data处理异常:{stock[1]}代码{e}")
51 | except Exception as e:
52 | logging.error(f"singleton.stock_hist_data处理异常:{e}")
53 | if not _data:
54 | self.data = None
55 | else:
56 | self.data = _data
57 |
58 | def get_data(self):
59 | return self.data
60 |
--------------------------------------------------------------------------------
/instock/core/strategy/parking_apron.py:
--------------------------------------------------------------------------------
1 | #!/usr/local/bin/python
2 | # -*- coding: utf-8 -*-
3 |
4 | from datetime import datetime
5 | from instock.core.strategy import turtle_trade
6 |
7 | __author__ = 'myh '
8 | __date__ = '2023/3/10 '
9 |
10 |
11 | # 停机坪
12 | # 1.最近15日有涨幅大于9.5%,且必须是放量上涨
13 | # 2.紧接的下个交易日必须高开,收盘价必须上涨,且与开盘价不能大于等于相差3%
14 | # 3.接下2、3个交易日必须高开,收盘价必须上涨,且与开盘价不能大于等于相差3%,且每天涨跌幅在5%间
15 | def check(code_name, data, date=None, threshold=15):
16 | origin_data = data
17 | if date is None:
18 | end_date = code_name[0]
19 | else:
20 | end_date = date.strftime("%Y-%m-%d")
21 | if end_date is not None:
22 | mask = (data['date'] <= end_date)
23 | data = data.loc[mask]
24 | if len(data.index) < threshold:
25 | return False
26 |
27 | data = data.tail(n=threshold)
28 |
29 | limitup_row = [1000000, '']
30 | # 找出涨停日
31 | for _close, _p_change, _date in zip(data['close'].values, data['p_change'].values, data['date'].values):
32 | if _p_change > 9.5:
33 | if turtle_trade.check_enter(code_name, origin_data, date=datetime.date(datetime.strptime(_date, '%Y-%m-%d')), threshold=threshold):
34 | limitup_row[0] = _close
35 | limitup_row[1] = _date
36 | if check_internal(data, limitup_row):
37 | return True
38 | return False
39 |
40 | def check_internal(data, limitup_row):
41 | limitup_price = limitup_row[0]
42 | limitup_end = data.loc[(data['date'] > limitup_row[1])]
43 | limitup_end = limitup_end.head(n=3)
44 | if len(limitup_end.index) < 3:
45 | return False
46 |
47 | consolidation_day1 = limitup_end.iloc[0]
48 | consolidation_day23 = limitup_end.tail(n=2)
49 |
50 | if not (consolidation_day1['close'] > limitup_price and consolidation_day1['open'] > limitup_price and
51 | 0.97 < consolidation_day1['close'] / consolidation_day1['open'] < 1.03):
52 | return False
53 |
54 | for _close, _p_change, _open in zip(consolidation_day23['close'].values, consolidation_day23['p_change'].values, consolidation_day23['open'].values):
55 | if not (0.97 < (_close / _open) < 1.03 and -5 < _p_change < 5
56 | and _close > limitup_price and _open > limitup_price):
57 | return False
58 |
59 | return True
60 |
--------------------------------------------------------------------------------
/instock/trade/strategies/stratey1.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | # -*- coding: utf-8 -*-
3 |
4 | import os.path
5 | import datetime as dt
6 | from dateutil import tz
7 | from instock.trade.robot.infrastructure.default_handler import DefaultLogHandler
8 | from instock.trade.robot.infrastructure.strategy_template import StrategyTemplate
9 |
10 | __author__ = 'myh '
11 | __date__ = '2023/4/10 '
12 |
13 |
14 | class Strategy(StrategyTemplate):
15 | name = 'stratey1'
16 |
17 | def init(self):
18 | # 通过下面的方式来获取时间戳
19 | # now_dt = self.clock_engine.now_dt
20 | # now = self.clock_engine.now
21 | # now = time.time()
22 |
23 | # 注册时钟事件
24 | clock_type = self.name
25 | moment = dt.time(14, 54, 30, tzinfo=tz.tzlocal())
26 | self.clock_engine.register_moment(clock_type, moment)
27 |
28 | # 注册时钟间隔事件, 不在交易阶段也会触发, clock_type == minute_interval
29 | minute_interval = 1.5
30 | self.clock_engine.register_interval(minute_interval, trading=False)
31 |
32 | def strategy(self):
33 | buy_stock = [('000001', 1, 100)]
34 | sell_stock = [('000001', 100, 100)]
35 | # --------写交易策略---------
36 |
37 | # --------写交易策略---------
38 | for buy in buy_stock:
39 | self.user.buy(buy[0], price=buy[1], amount=buy[3])
40 | for sell in sell_stock:
41 | self.user.sell(sell[0], price=sell[1], amount=sell[3])
42 |
43 | self.log.info('检查持仓')
44 | self.log.info(self.user.balance)
45 | self.log.info('\n')
46 |
47 | def clock(self, event):
48 | """在交易时间会定时推送 clock 事件
49 | :param event: event.data.clock_event 为 [0.5, 1, 3, 5, 15, 30, 60] 单位为分钟, ['open', 'close'] 为开市、收市
50 | event.data.trading_state bool 是否处于交易时间
51 | """
52 | if event.data.clock_event == self.name:
53 | self.strategy()
54 |
55 | def log_handler(self):
56 | """自定义 log 记录方式"""
57 | cpath_current = os.path.dirname(os.path.dirname(__file__))
58 | cpath = os.path.abspath(os.path.join(cpath_current, os.pardir))
59 | log_filepath = os.path.join(cpath, 'log', f'{self.name}.log')
60 | return DefaultLogHandler(self.name, log_type='file', filepath=log_filepath)
61 |
62 | def shutdown(self):
63 | """
64 | 关闭进程前的调用
65 | :return:
66 | """
67 | self.log.info("假装在关闭前保存了策略数据")
68 |
--------------------------------------------------------------------------------
/instock/job/basic_data_daily_job.py:
--------------------------------------------------------------------------------
1 | #!/usr/local/bin/python3
2 | # -*- coding: utf-8 -*-
3 |
4 | import logging
5 | import os.path
6 | import sys
7 |
8 | cpath_current = os.path.dirname(os.path.dirname(__file__))
9 | cpath = os.path.abspath(os.path.join(cpath_current, os.pardir))
10 | sys.path.append(cpath)
11 | import instock.lib.run_template as runt
12 | import instock.core.tablestructure as tbs
13 | import instock.lib.database as mdb
14 | import instock.core.stockfetch as stf
15 | from instock.core.singleton_stock import stock_data
16 |
17 | __author__ = 'myh '
18 | __date__ = '2023/3/10 '
19 |
20 |
21 | # 股票实时行情数据。
22 | def save_nph_stock_spot_data(date, before=True):
23 | if before:
24 | return
25 | # 股票列表
26 | try:
27 | data = stock_data(date).get_data()
28 | if data is None or len(data.index) == 0:
29 | return
30 |
31 | table_name = tbs.TABLE_CN_STOCK_SPOT['name']
32 | # 删除老数据。
33 | if mdb.checkTableIsExist(table_name):
34 | del_sql = f"DELETE FROM `{table_name}` where `date` = '{date}'"
35 | mdb.executeSql(del_sql)
36 | cols_type = None
37 | else:
38 | cols_type = tbs.get_field_types(tbs.TABLE_CN_STOCK_SPOT['columns'])
39 |
40 | mdb.insert_db_from_df(data, table_name, cols_type, False, "`date`,`code`")
41 |
42 | except Exception as e:
43 | logging.error(f"basic_data_daily_job.save_stock_spot_data处理异常:{e}")
44 |
45 |
46 | # 基金实时行情数据。
47 | def save_nph_etf_spot_data(date, before=True):
48 | if before:
49 | return
50 | # 股票列表
51 | try:
52 | data = stf.fetch_etfs(date)
53 | if data is None or len(data.index) == 0:
54 | return
55 |
56 | table_name = tbs.TABLE_CN_ETF_SPOT['name']
57 | # 删除老数据。
58 | if mdb.checkTableIsExist(table_name):
59 | del_sql = f"DELETE FROM `{table_name}` where `date` = '{date}'"
60 | mdb.executeSql(del_sql)
61 | cols_type = None
62 | else:
63 | cols_type = tbs.get_field_types(tbs.TABLE_CN_ETF_SPOT['columns'])
64 |
65 | mdb.insert_db_from_df(data, table_name, cols_type, False, "`date`,`code`")
66 | except Exception as e:
67 | logging.error(f"basic_data_daily_job.save_nph_etf_spot_data处理异常:{e}")
68 |
69 |
70 | def main():
71 | runt.run_with_args(save_nph_stock_spot_data)
72 | runt.run_with_args(save_nph_etf_spot_data)
73 |
74 |
75 | # main函数入口
76 | if __name__ == '__main__':
77 | main()
78 |
--------------------------------------------------------------------------------
/instock/trade/robot/engine/event_engine.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | # -*- coding: utf-8 -*-
3 |
4 |
5 | from collections import defaultdict
6 | from queue import Queue, Empty
7 | from threading import Thread
8 |
9 | __author__ = 'myh '
10 | __date__ = '2023/4/10 '
11 |
12 |
13 | class Event:
14 | def __init__(self, event_type, data=None):
15 | self.event_type = event_type
16 | self.data = data
17 |
18 |
19 | class EventEngine:
20 | """事件驱动引擎"""
21 |
22 | def __init__(self):
23 | """初始化事件引擎"""
24 | # 事件队列
25 | self.__queue = Queue()
26 |
27 | # 事件引擎开关
28 | self.__active = False
29 |
30 | # 事件引擎处理线程
31 | self.__thread = Thread(target=self.__run, name="EventEngine.__thread")
32 |
33 | # 事件字典,key 为时间, value 为对应监听事件函数的列表
34 | self.__handlers = defaultdict(list)
35 |
36 | def __run(self):
37 | """启动引擎"""
38 | while self.__active:
39 | try:
40 | event = self.__queue.get(block=True, timeout=1)
41 | handle_thread = Thread(target=self.__process, name="EventEngine.__process", args=(event,))
42 | handle_thread.start()
43 | except Empty:
44 | pass
45 |
46 | def __process(self, event):
47 | """事件处理"""
48 | # 检查该事件是否有对应的处理函数
49 | if event.event_type in self.__handlers:
50 | # 若存在,则按顺序将时间传递给处理函数执行
51 | for handler in self.__handlers[event.event_type]:
52 | handler(event)
53 |
54 | def start(self):
55 | """引擎启动"""
56 | self.__active = True
57 | self.__thread.start()
58 |
59 | def stop(self):
60 | """停止引擎"""
61 | self.__active = False
62 | self.__thread.join()
63 |
64 | def register(self, event_type, handler):
65 | """注册事件处理函数监听"""
66 | if handler not in self.__handlers[event_type]:
67 | self.__handlers[event_type].append(handler)
68 |
69 | def unregister(self, event_type, handler):
70 | """注销事件处理函数"""
71 | handler_list = self.__handlers.get(event_type)
72 | if handler_list is None:
73 | return
74 | if handler in handler_list:
75 | handler_list.remove(handler)
76 | if len(handler_list) == 0:
77 | self.__handlers.pop(event_type)
78 |
79 | def put(self, event):
80 | self.__queue.put(event)
81 |
82 | @property
83 | def queue_size(self):
84 | return self.__queue.qsize()
85 |
--------------------------------------------------------------------------------
/instock/lib/run_template.py:
--------------------------------------------------------------------------------
1 | #!/usr/local/bin/python
2 | # -*- coding: utf-8 -*-
3 |
4 |
5 | import logging
6 | import datetime
7 | import concurrent.futures
8 | import sys
9 | import time
10 | import instock.lib.trade_time as trd
11 |
12 | __author__ = 'myh '
13 | __date__ = '2023/3/10 '
14 |
15 |
16 | # 通用函数,获得日期参数,支持批量作业。
17 | def run_with_args(run_fun, *args):
18 | if len(sys.argv) == 3:
19 | # 区间作业 python xxx.py 2023-03-01 2023-03-21
20 | tmp_year, tmp_month, tmp_day = sys.argv[1].split("-")
21 | start_date = datetime.datetime(int(tmp_year), int(tmp_month), int(tmp_day)).date()
22 | tmp_year, tmp_month, tmp_day = sys.argv[2].split("-")
23 | end_date = datetime.datetime(int(tmp_year), int(tmp_month), int(tmp_day)).date()
24 | run_date = start_date
25 | try:
26 | with concurrent.futures.ThreadPoolExecutor() as executor:
27 | while run_date <= end_date:
28 | if trd.is_trade_date(run_date):
29 | executor.submit(run_fun, run_date, *args)
30 | time.sleep(2)
31 | run_date += datetime.timedelta(days=1)
32 | except Exception as e:
33 | logging.error(f"run_template.run_with_args处理异常:{run_fun}{sys.argv}{e}")
34 | elif len(sys.argv) == 2:
35 | # N个时间作业 python xxx.py 2023-03-01,2023-03-02
36 | dates = sys.argv[1].split(',')
37 | try:
38 | with concurrent.futures.ThreadPoolExecutor() as executor:
39 | for date in dates:
40 | tmp_year, tmp_month, tmp_day = date.split("-")
41 | run_date = datetime.datetime(int(tmp_year), int(tmp_month), int(tmp_day)).date()
42 | if trd.is_trade_date(run_date):
43 | executor.submit(run_fun, run_date, *args)
44 | time.sleep(2)
45 | except Exception as e:
46 | logging.error(f"run_template.run_with_args处理异常:{run_fun}{sys.argv}{e}")
47 | else:
48 | # 当前时间作业 python xxx.py
49 | try:
50 | run_date, run_date_nph = trd.get_trade_date_last()
51 | if run_fun.__name__.startswith('save_nph'):
52 | run_fun(run_date_nph, False)
53 | elif run_fun.__name__.startswith('save_after_close'):
54 | run_fun(run_date, *args)
55 | else:
56 | run_fun(run_date_nph, *args)
57 | except Exception as e:
58 | logging.error(f"run_template.run_with_args处理异常:{run_fun}{sys.argv}{e}")
59 |
--------------------------------------------------------------------------------
/instock/web/dataIndicatorsHandler.py:
--------------------------------------------------------------------------------
1 | #!/usr/local/bin/python3
2 | # -*- coding: utf-8 -*-
3 |
4 | from abc import ABC
5 | from tornado import gen
6 | import logging
7 | import instock.core.stockfetch as stf
8 | import instock.core.kline.visualization as vis
9 | import instock.web.base as webBase
10 |
11 | __author__ = 'myh '
12 | __date__ = '2023/3/10 '
13 |
14 |
15 | # 获得页面数据。
16 | class GetDataIndicatorsHandler(webBase.BaseHandler, ABC):
17 | @gen.coroutine
18 | def get(self):
19 | code = self.get_argument("code", default=None, strip=False)
20 | date = self.get_argument("date", default=None, strip=False)
21 | name = self.get_argument("name", default=None, strip=False)
22 | comp_list = []
23 | try:
24 | if code.startswith(('1', '5')):
25 | stock = stf.fetch_etf_hist((date, code))
26 | else:
27 | stock = stf.fetch_stock_hist((date, code))
28 | if stock is None:
29 | return
30 |
31 | pk = vis.get_plot_kline(code, stock, date, name)
32 | if pk is None:
33 | return
34 |
35 | comp_list.append(pk)
36 | except Exception as e:
37 | logging.error(f"dataIndicatorsHandler.GetDataIndicatorsHandler处理异常:{e}")
38 |
39 | self.render("stock_indicators.html", comp_list=comp_list,
40 | leftMenu=webBase.GetLeftMenu(self.request.uri))
41 |
42 |
43 | # 关注股票。
44 | class SaveCollectHandler(webBase.BaseHandler, ABC):
45 | @gen.coroutine
46 | def get(self):
47 | import datetime
48 | import instock.core.tablestructure as tbs
49 | code = self.get_argument("code", default=None, strip=False)
50 | otype = self.get_argument("otype", default=None, strip=False)
51 | try:
52 | table_name = tbs.TABLE_CN_STOCK_ATTENTION['name']
53 | if otype == '1':
54 | # sql = f"DELETE FROM `{table_name}` WHERE `code` = '{code}'"
55 | sql = f"DELETE FROM `{table_name}` WHERE `code` = %s"
56 | self.db.query(sql,code)
57 | else:
58 | # sql = f"INSERT INTO `{table_name}`(`datetime`, `code`) VALUE('{datetime.datetime.now()}','{code}')"
59 | sql = f"INSERT INTO `{table_name}`(`datetime`, `code`) VALUE(%s, %s)"
60 | self.db.query(sql,datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f"),code)
61 | except Exception as e:
62 | err = {"error": str(e)}
63 | # logging.info(err)
64 | # self.write(err)
65 | # return
66 | self.write("{\"data\":[{}]}")
--------------------------------------------------------------------------------
/instock/web/dataTableHandler.py:
--------------------------------------------------------------------------------
1 | #!/usr/local/bin/python3
2 | # -*- coding: utf-8 -*-
3 |
4 |
5 | import json
6 | from abc import ABC
7 | from tornado import gen
8 | # import logging
9 | import datetime
10 | import instock.lib.trade_time as trd
11 | import instock.core.singleton_stock_web_module_data as sswmd
12 | import instock.web.base as webBase
13 |
14 | __author__ = 'myh '
15 | __date__ = '2023/3/10 '
16 |
17 |
18 | class MyEncoder(json.JSONEncoder):
19 |
20 | def default(self, obj):
21 | if isinstance(obj, bytes):
22 | return "是" if ord(obj) == 1 else "否"
23 | elif isinstance(obj, datetime.date):
24 | delta = datetime.datetime.combine(obj, datetime.time.min) - datetime.datetime(1899, 12, 30)
25 | return f'/OADate({float(delta.days) + (float(delta.seconds) / 86400)})/' # 86,400 seconds in day
26 | # return obj.isoformat()
27 | else:
28 | return json.JSONEncoder.default(self, obj)
29 |
30 |
31 | # 获得页面数据。
32 | class GetStockHtmlHandler(webBase.BaseHandler, ABC):
33 | @gen.coroutine
34 | def get(self):
35 | name = self.get_argument("table_name", default=None, strip=False)
36 | web_module_data = sswmd.stock_web_module_data().get_data(name)
37 | run_date, run_date_nph = trd.get_trade_date_last()
38 | if web_module_data.is_realtime:
39 | date_now_str = run_date_nph.strftime("%Y-%m-%d")
40 | else:
41 | date_now_str = run_date.strftime("%Y-%m-%d")
42 | self.render("stock_web.html", web_module_data=web_module_data, date_now=date_now_str,
43 | leftMenu=webBase.GetLeftMenu(self.request.uri))
44 |
45 |
46 | # 获得股票数据内容。
47 | class GetStockDataHandler(webBase.BaseHandler, ABC):
48 | def get(self):
49 | name = self.get_argument("name", default=None, strip=False)
50 | date = self.get_argument("date", default=None, strip=False)
51 | web_module_data = sswmd.stock_web_module_data().get_data(name)
52 | self.set_header('Content-Type', 'application/json;charset=UTF-8')
53 |
54 | if date is None:
55 | where = ""
56 | else:
57 | # where = f" WHERE `date` = '{date}'"
58 | where = f" WHERE `date` = %s"
59 |
60 | order_by = ""
61 | if web_module_data.order_by is not None:
62 | order_by = f" ORDER BY {web_module_data.order_by}"
63 |
64 | order_columns = ""
65 | if web_module_data.order_columns is not None:
66 | order_columns = f",{web_module_data.order_columns}"
67 |
68 | sql = f" SELECT *{order_columns} FROM `{web_module_data.table_name}`{where}{order_by}"
69 | data = self.db.query(sql,date)
70 |
71 | self.write(json.dumps(data, cls=MyEncoder))
72 |
--------------------------------------------------------------------------------
/instock/core/crawling/stock_selection.py:
--------------------------------------------------------------------------------
1 | # -*- coding:utf-8 -*-
2 | # !/usr/bin/env python
3 |
4 | import math
5 | import pandas as pd
6 | import requests
7 | import instock.core.tablestructure as tbs
8 |
9 | __author__ = 'myh '
10 | __date__ = '2023/5/9 '
11 |
12 |
13 | def stock_selection() -> pd.DataFrame:
14 | """
15 | 东方财富网-个股-选股器
16 | https://data.eastmoney.com/xuangu/
17 | :return: 选股器
18 | :rtype: pandas.DataFrame
19 | """
20 | cols = tbs.TABLE_CN_STOCK_SELECTION['columns']
21 | page_size = 50
22 | page_current = 1
23 | sty = "" # 初始值 "SECUCODE,SECURITY_CODE,SECURITY_NAME_ABBR,CHANGE_RATE"
24 | for k in cols:
25 | sty = f"{sty},{cols[k]['map']}"
26 | url = "https://data.eastmoney.com/dataapi/xuangu/list"
27 | params = {
28 | "sty": sty[1:],
29 | "filter": "(MARKET+in+(\"上交所主板\",\"深交所主板\",\"深交所创业板\"))(NEW_PRICE>0)",
30 | "p": page_current,
31 | "ps": page_size,
32 | "source": "SELECT_SECURITIES",
33 | "client": "WEB"
34 | }
35 | r = requests.get(url, params=params)
36 | data_json = r.json()
37 | data = data_json["result"]["data"]
38 | if not data:
39 | return pd.DataFrame()
40 |
41 | data_count = data_json["result"]["count"]
42 | page_count = math.ceil(data_count/page_size)
43 | while page_count > 1:
44 | page_current = page_current + 1
45 | params["p"] = page_current
46 | r = requests.get(url, params=params)
47 | data_json = r.json()
48 | _data = data_json["result"]["data"]
49 | data.extend(_data)
50 | page_count =page_count - 1
51 |
52 | temp_df = pd.DataFrame(data)
53 |
54 | mask = ~temp_df['CONCEPT'].isna()
55 | temp_df.loc[mask, 'CONCEPT'] = temp_df.loc[mask, 'CONCEPT'].apply(lambda x: ', '.join(x))
56 | mask = ~temp_df['STYLE'].isna()
57 | temp_df.loc[mask, 'STYLE'] = temp_df.loc[mask, 'STYLE'].apply(lambda x: ', '.join(x))
58 |
59 | for k in cols:
60 | t = tbs.get_field_type_name(cols[k]["type"])
61 | if t == 'numeric':
62 | temp_df[cols[k]["map"]] = pd.to_numeric(temp_df[cols[k]["map"]], errors="coerce")
63 | elif t == 'datetime':
64 | temp_df[cols[k]["map"]] = pd.to_datetime(temp_df[cols[k]["map"]], errors="coerce").dt.date
65 |
66 | return temp_df
67 |
68 |
69 | def stock_selection_params():
70 | """
71 | 东方财富网-个股-选股器-选股指标
72 | https://data.eastmoney.com/xuangu/
73 | :return: 选股器-选股指标
74 | :rtype: pandas.DataFrame
75 | """
76 | url = "https://datacenter-web.eastmoney.com/wstock/selection/api/data/get"
77 | params = {
78 | "type": "RPTA_PCNEW_WHOLE",
79 | "sty": "ALL",
80 | "p": 1,
81 | "ps": 50000,
82 | "source": "SELECT_SECURITIES",
83 | "client": "WEB"
84 | }
85 |
86 | r = requests.get(url, params=params)
87 | data_json = r.json()
88 | zxzb = data_json["zxzb"] # 指标
89 | print(zxzb)
90 |
91 |
92 | if __name__ == "__main__":
93 | stock_selection_df = stock_selection()
94 | print(stock_selection)
95 |
--------------------------------------------------------------------------------
/instock/core/strategy/backtrace_ma250.py:
--------------------------------------------------------------------------------
1 | #!/usr/local/bin/python
2 | # -*- coding: utf-8 -*-
3 |
4 | import numpy as np
5 | import talib as tl
6 | from datetime import datetime, timedelta
7 |
8 | __author__ = 'myh '
9 | __date__ = '2023/3/10 '
10 |
11 |
12 | # 回踩年线
13 | # 1.时间段:前段=最近60交易日最高收盘价之前交易日(长度>0),后段=最高价当日及后面的交易日
14 | # 2.前段由年线(250日)以下向上突破
15 | # 3.后段必须在年线以上运行,且后段最低价日与最高价日相差必须在10-50日间
16 | # 4.回踩伴随缩量:最高价日交易量/后段最低价日交易量>2,后段最低价/最高价<0.8
17 | def check(code_name, data, date=None, threshold=60):
18 | if date is None:
19 | end_date = code_name[0]
20 | else:
21 | end_date = date.strftime("%Y-%m-%d")
22 |
23 | if end_date is not None:
24 | mask = (data['date'] <= end_date)
25 | data = data.loc[mask].copy()
26 | if len(data.index) < 250:
27 | return False
28 |
29 | data.loc[:, 'ma250'] = tl.MA(data['close'].values, timeperiod=250)
30 | data['ma250'].values[np.isnan(data['ma250'].values)] = 0.0
31 |
32 | data = data.tail(n=threshold)
33 |
34 | # 区间最低点
35 | lowest_row = [1000000, 0, '']
36 | # 区间最高点
37 | highest_row = [0, 0, '']
38 | # 近期低点
39 | recent_lowest_row = [1000000, 0, '']
40 |
41 | # 计算区间最高、最低价格
42 | for _close, _volume, _date in zip(data['close'].values, data['volume'].values, data['date'].values):
43 | if _close > highest_row[0]:
44 | highest_row[0] = _close
45 | highest_row[1] = _volume
46 | highest_row[2] = _date
47 | elif _close < lowest_row[0]:
48 | lowest_row[0] = _close
49 | lowest_row[1] = _volume
50 | lowest_row[2] = _date
51 |
52 | if lowest_row[1] == 0 or highest_row[1] == 0:
53 | return False
54 |
55 | data_front = data.loc[(data['date'] < highest_row[2])]
56 | data_end = data.loc[(data['date'] >= highest_row[2])]
57 |
58 | if data_front.empty:
59 | return False
60 | # 前半段由年线以下向上突破
61 | if not (data_front.iloc[0]['close'] < data_front.iloc[0]['ma250'] and
62 | data_front.iloc[-1]['close'] > data_front.iloc[-1]['ma250']):
63 | return False
64 |
65 | if not data_end.empty:
66 | # 后半段必须在年线以上运行(回踩年线)
67 | for _close, _volume, _date, _ma250 in zip(data_end['close'].values, data_end['volume'].values, data_end['date'].values, data_end['ma250'].values):
68 | if _close < _ma250:
69 | return False
70 | if _close < recent_lowest_row[0]:
71 | recent_lowest_row[0] = _close
72 | recent_lowest_row[1] = _volume
73 | recent_lowest_row[2] = _date
74 |
75 | date_diff = datetime.date(datetime.strptime(recent_lowest_row[2], '%Y-%m-%d')) - \
76 | datetime.date(datetime.strptime(highest_row[2], '%Y-%m-%d'))
77 |
78 | if not (timedelta(days=10) <= date_diff <= timedelta(days=50)):
79 | return False
80 | # 回踩伴随缩量
81 | vol_ratio = highest_row[1] / recent_lowest_row[1]
82 | back_ratio = recent_lowest_row[0] / highest_row[0]
83 |
84 | if not (vol_ratio > 2 and back_ratio < 0.8):
85 | return False
86 |
87 | return True
88 |
--------------------------------------------------------------------------------
/instock/web/web_service.py:
--------------------------------------------------------------------------------
1 | #!/usr/local/bin/python3
2 | # -*- coding: utf-8 -*-
3 |
4 | import logging
5 | import os.path
6 | import sys
7 | from abc import ABC
8 |
9 | import tornado.escape
10 | import tornado.httpserver
11 | import tornado.ioloop
12 | import tornado.options
13 | from tornado import gen
14 |
15 | # 在项目运行时,临时将项目路径添加到环境变量
16 | cpath_current = os.path.dirname(os.path.dirname(__file__))
17 | cpath = os.path.abspath(os.path.join(cpath_current, os.pardir))
18 | sys.path.append(cpath)
19 | log_path = os.path.join(cpath_current, 'log')
20 | if not os.path.exists(log_path):
21 | os.makedirs(log_path)
22 | logging.basicConfig(format='%(asctime)s %(message)s', filename=os.path.join(log_path, 'stock_web.log'))
23 | logging.getLogger().setLevel(logging.ERROR)
24 | import instock.lib.torndb as torndb
25 | import instock.lib.database as mdb
26 | import instock.lib.version as version
27 | import instock.web.dataTableHandler as dataTableHandler
28 | import instock.web.dataIndicatorsHandler as dataIndicatorsHandler
29 | import instock.web.base as webBase
30 |
31 | __author__ = 'myh '
32 | __date__ = '2023/3/10 '
33 |
34 |
35 | class Application(tornado.web.Application):
36 | def __init__(self):
37 | handlers = [
38 | # 设置路由
39 | (r"/", HomeHandler),
40 | (r"/instock/", HomeHandler),
41 | # 使用datatable 展示报表数据模块。
42 | (r"/instock/api_data", dataTableHandler.GetStockDataHandler),
43 | (r"/instock/data", dataTableHandler.GetStockHtmlHandler),
44 | # 获得股票指标数据。
45 | (r"/instock/data/indicators", dataIndicatorsHandler.GetDataIndicatorsHandler),
46 | # 加入关注
47 | (r"/instock/control/attention", dataIndicatorsHandler.SaveCollectHandler),
48 | ]
49 | settings = dict( # 配置
50 | template_path=os.path.join(os.path.dirname(__file__), "templates"),
51 | static_path=os.path.join(os.path.dirname(__file__), "static"),
52 | xsrf_cookies=False, # True,
53 | # cookie加密
54 | cookie_secret="027bb1b670eddf0392cdda8709268a17b58b7",
55 | debug=True,
56 | )
57 | super(Application, self).__init__(handlers, **settings)
58 | # Have one global connection to the blog DB across all handlers
59 | self.db = torndb.Connection(**mdb.MYSQL_CONN_TORNDB)
60 |
61 |
62 | # 首页handler。
63 | class HomeHandler(webBase.BaseHandler, ABC):
64 | @gen.coroutine
65 | def get(self):
66 | self.render("index.html",
67 | stockVersion=version.__version__,
68 | leftMenu=webBase.GetLeftMenu(self.request.uri))
69 |
70 |
71 | def main():
72 | # tornado.options.parse_command_line()
73 | tornado.options.options.logging = None
74 |
75 | http_server = tornado.httpserver.HTTPServer(Application())
76 | port = 9988
77 | http_server.listen(port)
78 |
79 | print(f"服务已启动,web地址 : http://localhost:{port}/")
80 | logging.error(f"服务已启动,web地址 : http://localhost:{port}/")
81 |
82 | tornado.ioloop.IOLoop.current().start()
83 |
84 |
85 | if __name__ == "__main__":
86 | main()
87 |
--------------------------------------------------------------------------------
/docker/Dockerfile:
--------------------------------------------------------------------------------
1 | # 基础镜像
2 | # https://hub.docker.com/_/python/tags?page=1&name=3.11-slim-bullseye
3 | FROM docker.io/python:3.11-slim-bullseye
4 |
5 | MAINTAINER myh
6 | #增加语言utf-8
7 | ENV LANG=zh_CN.UTF-8
8 | ENV LC_CTYPE=zh_CN.UTF-8
9 | ENV LC_ALL=C
10 | ENV PYTHONPATH=/data/InStock
11 | EXPOSE 9988
12 |
13 | # 使用国内镜像地址加速。修改debian apt更新地址,pip地址,设置时区
14 | # https://opsx.alibaba.com/mirror
15 | # https://mirrors.tuna.tsinghua.edu.cn/help/pypi/
16 | # cat /etc/apt/sources.list 参考原始地址,再确定怎么样替换
17 | # 安装依赖库
18 | # apt-get autoremove -y 删除没有用的依赖lib
19 | # apt-get --purge remove 软件包名称 , 删除已安装包(不保留配置文件)
20 | RUN sed -i "s@http://\(deb\|security\).debian.org@https://mirrors.aliyun.com@g" /etc/apt/sources.list && \
21 | echo "[global]\n\
22 | index-url = https://mirrors.aliyun.com/pypi/simple\n\
23 | trusted-host = mirrors.aliyun.com" > /etc/pip.conf && \
24 | ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && \
25 | echo "Asia/Shanghai" > /etc/timezone && \
26 | apt-get update && \
27 | apt-get install -y cron gcc make python3-dev default-libmysqlclient-dev build-essential pkg-config curl && \
28 | pip install supervisor && \
29 | pip install mysqlclient && \
30 | pip install requests && \
31 | pip install arrow && \
32 | pip install numpy && \
33 | pip install SQLAlchemy && \
34 | pip install PyMySQL && \
35 | pip install Logbook && \
36 | pip install python_dateutil && \
37 | pip install py_mini_racer && \
38 | pip install tqdm && \
39 | pip install beautifulsoup4 && \
40 | pip install bokeh && \
41 | pip install pandas && \
42 | pip install tornado && \
43 | pip install mini-racer && \
44 | pip install easytrader && \
45 | mkdir ta-lib && \
46 | curl -SL $(curl -s https://api.github.com/repos/ta-lib/ta-lib/releases/latest | grep browser_download_url | cut -d'"' -f4 |grep -E 'tar.gz$') | tar -xz --strip-components=1 -C ./ta-lib && \
47 | cd ta-lib/ && \
48 | ./configure && \
49 | make && \
50 | make install && \
51 | cd .. && \
52 | pip install TA-Lib && \
53 | rm -rf ta-lib* && \
54 | apt-get --purge remove -y gcc make python3-dev default-libmysqlclient-dev curl && \
55 | rm -rf /root/.cache/* && rm -rf /var/lib/apt/lists/* && apt-get clean && apt-get autoclean && apt-get autoremove -y
56 |
57 | WORKDIR /data
58 | #InStock软件
59 | COPY stock /data/InStock
60 | COPY cron/cron.hourly /etc/cron.hourly
61 | COPY cron/cron.workdayly /etc/cron.workdayly
62 | COPY cron/cron.monthly /etc/cron.monthly
63 |
64 | #add cron sesrvice.
65 | #任务调度
66 | RUN chmod 755 /data/InStock/instock/bin/run_*.sh && \
67 | chmod 755 /etc/cron.hourly/* && chmod 755 /etc/cron.workdayly/* && chmod 755 /etc/cron.monthly/* && \
68 | echo "SHELL=/bin/sh \n\
69 | PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin \n\
70 | # min hour day month weekday command \n\
71 | */30 9,10,11,13,14,15 * * 1-5 /bin/run-parts /etc/cron.hourly \n\
72 | 30 17 * * 1-5 /bin/run-parts /etc/cron.workdayly \n\
73 | 30 10 * * 3,6 /bin/run-parts /etc/cron.monthly \n" > /var/spool/cron/crontabs/root && \
74 | chmod 600 /var/spool/cron/crontabs/root
75 |
76 | ENTRYPOINT ["supervisord","-n","-c","/data/InStock/supervisor/supervisord.conf"]
--------------------------------------------------------------------------------
/instock/job/klinepattern_data_daily_job.py:
--------------------------------------------------------------------------------
1 | #!/usr/local/bin/python3
2 | # -*- coding: utf-8 -*-
3 |
4 |
5 | import logging
6 | import concurrent.futures
7 | import pandas as pd
8 | import os.path
9 | import sys
10 |
11 | cpath_current = os.path.dirname(os.path.dirname(__file__))
12 | cpath = os.path.abspath(os.path.join(cpath_current, os.pardir))
13 | sys.path.append(cpath)
14 | import instock.lib.run_template as runt
15 | import instock.core.tablestructure as tbs
16 | import instock.lib.database as mdb
17 | from instock.core.singleton_stock import stock_hist_data
18 | import instock.core.pattern.pattern_recognitions as kpr
19 |
20 | __author__ = 'myh '
21 | __date__ = '2023/3/10 '
22 |
23 |
24 | def prepare(date):
25 | try:
26 | stocks_data = stock_hist_data(date=date).get_data()
27 | if stocks_data is None:
28 | return
29 | results = run_check(stocks_data, date=date)
30 | if results is None:
31 | return
32 |
33 | table_name = tbs.TABLE_CN_STOCK_KLINE_PATTERN['name']
34 | # 删除老数据。
35 | if mdb.checkTableIsExist(table_name):
36 | del_sql = f"DELETE FROM `{table_name}` where `date` = '{date}'"
37 | mdb.executeSql(del_sql)
38 | cols_type = None
39 | else:
40 | cols_type = tbs.get_field_types(tbs.TABLE_CN_STOCK_KLINE_PATTERN['columns'])
41 |
42 | dataKey = pd.DataFrame(results.keys())
43 | _columns = tuple(tbs.TABLE_CN_STOCK_FOREIGN_KEY['columns'])
44 | dataKey.columns = _columns
45 |
46 | dataVal = pd.DataFrame(results.values())
47 |
48 | data = pd.merge(dataKey, dataVal, on=['code'], how='left')
49 | # 单例,时间段循环必须改时间
50 | date_str = date.strftime("%Y-%m-%d")
51 | if date.strftime("%Y-%m-%d") != data.iloc[0]['date']:
52 | data['date'] = date_str
53 | mdb.insert_db_from_df(data, table_name, cols_type, False, "`date`,`code`")
54 |
55 | except Exception as e:
56 | logging.error(f"klinepattern_data_daily_job.prepare处理异常:{e}")
57 |
58 |
59 | def run_check(stocks, date=None, workers=40):
60 | data = {}
61 | columns = tbs.STOCK_KLINE_PATTERN_DATA['columns']
62 | data_column = columns
63 | try:
64 | with concurrent.futures.ThreadPoolExecutor(max_workers=workers) as executor:
65 | future_to_data = {executor.submit(kpr.get_pattern_recognition, k, stocks[k], data_column, date=date): k for k in stocks}
66 | for future in concurrent.futures.as_completed(future_to_data):
67 | stock = future_to_data[future]
68 | try:
69 | _data_ = future.result()
70 | if _data_ is not None:
71 | data[stock] = _data_
72 | except Exception as e:
73 | logging.error(f"klinepattern_data_daily_job.run_check处理异常:{stock[1]}代码{e}")
74 | except Exception as e:
75 | logging.error(f"klinepattern_data_daily_job.run_check处理异常:{e}")
76 | if not data:
77 | return None
78 | else:
79 | return data
80 |
81 |
82 | def main():
83 | # 使用方法传递。
84 | runt.run_with_args(prepare)
85 |
86 |
87 | # main函数入口
88 | if __name__ == '__main__':
89 | main()
90 |
--------------------------------------------------------------------------------
/.github/workflows/azure-container-webapp.yml:
--------------------------------------------------------------------------------
1 | # 当提交推送到默认分支时,此工作流将构建 Docker 容器并将其推送到 Azure Web 应用程序。
2 | #
3 | # 此工作流假设您已创建目标 Azure 应用服务 Web 应用。
4 | #相关说明,请参阅 https://docs.microsoft.com/en-us/azure/app-service/quickstart-custom-container?tabs=dotnet&pivots=container-linux
5 | #
6 | # 配置此工作流程:
7 | #
8 | # 1.下载Azure Web应用程序的发布配置文件。您可以从Azure门户中Web应用程序的概述页面下载此文件。
9 | #相关详细信息:https://docs.microsoft.com/en-us/azure/app-service/deploy-github-actions?tabs=applevel#generate-deployment-credentials
10 | #
11 | # 2. 在存储库中创建一个名为 AZURE_WEBAPP_PUBLISH_PROFILE 的密钥,将发布配置文件内容粘贴为密钥的值。
12 | # 有关获取发布配置文件的说明,请参阅:https://docs.microsoft.com/azure/app-service/deploy-github-actions#configure-the-github-secret
13 | #
14 | # 3.创建具有“repo”和“read:packages”权限的GitHub个人访问令牌。
15 | #
16 | # 4.在Azure Web应用程序上创建三个应用程序设置:
17 | # DOCKER_REGISTRY_SERVER_URL:将其设置为“https://ghcr.io”
18 | # DOCKER_REGISTRY_SERVER_USERNAME:将其设置为拥有存储库的GitHub用户名或组织
19 | # DOCKER_REGISTRY_SERVER_PASSWORD:将其设置为上一步中PAT令牌的值
20 | #
21 | # 5.更改 AZURE_WEBAPP_NAME 的值。
22 | #
23 | #相关Azure的GitHub Actions的更多信息:https://github.com/Azure/Actions
24 | # 有关 Azure Web Apps 部署操作的更多信息:https://github.com/Azure/webapps-deploy
25 | # 有关开始使用 GitHub Action 工作流部署到 Azure 的更多示例:https://github.com/Azure/actions-workflow-samples
26 |
27 | 名称:名称:构建容器并将其部署到 Azure Web App
28 |
29 | 环境:
30 | : AZURE_WEBAPP_NAME : your-app-name # 将其设置为您的 Azure Web 应用程序的名称# 将其设置为您的 Azure Web 应用程序的名称
31 |
32 | 在:
33 | 推:
34 | 分支: [ 分支:[ “主” ] “master” ]
35 | 工作流程_调度:
36 |
37 | 权限:
38 | 内容: 内容: 阅读
39 |
40 | 工作:
41 | 建造者:
42 | running-on : 运行:ubuntu-latest
43 |
44 | 脚步:
45 | -使用: - 使用:actions/checkout@v3
46 |
47 | -姓名 : - 名称:设置 Docker Buildx
48 | 使用: 使用: docker/setup-buildx-action@f95db51fddba0c2d1ec667646a06c2ce06100226 # v3.0.0# v3.0.0
49 |
50 | - name : - 名称:登录GitHubContainer
51 | 使用: docker/login-action@343f7c4344506bcbf9b4de18042ae17996df046d # v3.0.0# v3.0.0
52 | 和:
53 | 开花: 开花:ghcr.io
54 | 用户名: 用户名:$ { { github.actor } } { { github.actor } }
55 | 密码: 密码:$ { { github.token } } { { github.token } }
56 |
57 | -姓名 : - name:小写的存储库名称和用户名
58 | run : 运行: echo "REPO=${GITHUB_REPOSITORY,,}" >>$ { GITHUB_ENV } “REPO=$ { GITHUB_REPOSITORY , , } ” >>$ { GITHUB_ENV }
59 |
60 | -名称: -名称:建造容器将其容器容器中
61 | 使用: 使用: docker/build-push-action@0565240e2d4ab88bba5387d719585280857ece09 # v5.0.0# v5.0.0
62 | 和:
63 | 推:真
64 | 标签: 标签:ghcr.io/$ { { env.REPO } } : $ { { github.sha } } { { env.REPO } } : $ { { github.sha } }
65 | 文件: 文件:./Dockerfile
66 |
67 | 部署:
68 | 权限:
69 | 内容: 内容:无
70 | 连续运行 : 运行:ubuntu-latest
71 | 需求: 需求: 建设
72 | 环境:
73 | 名称:《发展》
74 | url : 网址:$ { { steps.deploy-to-webapp.outputs.webapp-url } } { { steps.deploy-to-webapp.outputs.webapp-url } }
75 |
76 | 脚步:
77 | -姓名 : - name:小写的存储库名称和用户名
78 | 运行:echo “REPO=$ { GITHUB_REPOSITORY , , } ” >>$ { GITHUB_ENV }
79 |
80 | -姓名:部署到Azure Web App
81 | ID :部署到webapp
82 | 用途:azure/webapps-deploy@v2
83 | 和:
84 | 应用程序名称:$ { { env.AZURE_WEBAPP_NAME } }
85 | 发布配置文件:$ { { Secrets.AZURE_WEBAPP_PUBLISH_PROFILE } }
86 | 图片:'ghcr.io/${{ env.REPO }}:${{ github.sha }}'
87 |
--------------------------------------------------------------------------------
/instock/job/strategy_data_daily_job.py:
--------------------------------------------------------------------------------
1 | #!/usr/local/bin/python3
2 | # -*- coding: utf-8 -*-
3 |
4 | import logging
5 | import concurrent.futures
6 | import pandas as pd
7 | import os.path
8 | import sys
9 |
10 | cpath_current = os.path.dirname(os.path.dirname(__file__))
11 | cpath = os.path.abspath(os.path.join(cpath_current, os.pardir))
12 | sys.path.append(cpath)
13 | import instock.lib.run_template as runt
14 | import instock.core.tablestructure as tbs
15 | import instock.lib.database as mdb
16 | from instock.core.singleton_stock import stock_hist_data
17 | from instock.core.stockfetch import fetch_stock_top_entity_data
18 |
19 | __author__ = 'myh '
20 | __date__ = '2023/3/10 '
21 |
22 |
23 | def prepare(date, strategy):
24 | try:
25 | stocks_data = stock_hist_data(date=date).get_data()
26 | if stocks_data is None:
27 | return
28 | table_name = strategy['name']
29 | strategy_func = strategy['func']
30 | results = run_check(strategy_func, table_name, stocks_data, date)
31 | if results is None:
32 | return
33 |
34 | # 删除老数据。
35 | if mdb.checkTableIsExist(table_name):
36 | del_sql = f"DELETE FROM `{table_name}` where `date` = '{date}'"
37 | mdb.executeSql(del_sql)
38 | cols_type = None
39 | else:
40 | cols_type = tbs.get_field_types(tbs.TABLE_CN_STOCK_STRATEGIES[0]['columns'])
41 |
42 | data = pd.DataFrame(results)
43 | columns = tuple(tbs.TABLE_CN_STOCK_FOREIGN_KEY['columns'])
44 | data.columns = columns
45 | _columns_backtest = tuple(tbs.TABLE_CN_STOCK_BACKTEST_DATA['columns'])
46 | data = pd.concat([data, pd.DataFrame(columns=_columns_backtest)])
47 | # 单例,时间段循环必须改时间
48 | date_str = date.strftime("%Y-%m-%d")
49 | if date.strftime("%Y-%m-%d") != data.iloc[0]['date']:
50 | data['date'] = date_str
51 | mdb.insert_db_from_df(data, table_name, cols_type, False, "`date`,`code`")
52 |
53 | except Exception as e:
54 | logging.error(f"strategy_data_daily_job.prepare处理异常:{strategy}策略{e}")
55 |
56 |
57 | def run_check(strategy_fun, table_name, stocks, date, workers=40):
58 | is_check_high_tight = False
59 | if strategy_fun.__name__ == 'check_high_tight':
60 | stock_tops = fetch_stock_top_entity_data(date)
61 | if stock_tops is not None:
62 | is_check_high_tight = True
63 | data = []
64 | try:
65 | with concurrent.futures.ThreadPoolExecutor(max_workers=workers) as executor:
66 | if is_check_high_tight:
67 | future_to_data = {executor.submit(strategy_fun, k, stocks[k], date=date, istop=(k[1] in stock_tops)): k for k in stocks}
68 | else:
69 | future_to_data = {executor.submit(strategy_fun, k, stocks[k], date=date): k for k in stocks}
70 | for future in concurrent.futures.as_completed(future_to_data):
71 | stock = future_to_data[future]
72 | try:
73 | if future.result():
74 | data.append(stock)
75 | except Exception as e:
76 | logging.error(f"strategy_data_daily_job.run_check处理异常:{stock[1]}代码{e}策略{table_name}")
77 | except Exception as e:
78 | logging.error(f"strategy_data_daily_job.run_check处理异常:{e}策略{table_name}")
79 | if not data:
80 | return None
81 | else:
82 | return data
83 |
84 |
85 | def main():
86 | # 使用方法传递。
87 | with concurrent.futures.ThreadPoolExecutor() as executor:
88 | for strategy in tbs.TABLE_CN_STOCK_STRATEGIES:
89 | executor.submit(runt.run_with_args, prepare, strategy)
90 |
91 |
92 | # main函数入口
93 | if __name__ == '__main__':
94 | main()
95 |
--------------------------------------------------------------------------------
/instock/job/backtest_data_daily_job.py:
--------------------------------------------------------------------------------
1 | #!/usr/local/bin/python3
2 | # -*- coding: utf-8 -*-
3 |
4 |
5 | import logging
6 | import concurrent.futures
7 | import pandas as pd
8 | import os.path
9 | import sys
10 | import datetime
11 |
12 | cpath_current = os.path.dirname(os.path.dirname(__file__))
13 | cpath = os.path.abspath(os.path.join(cpath_current, os.pardir))
14 | sys.path.append(cpath)
15 | import instock.core.tablestructure as tbs
16 | import instock.lib.database as mdb
17 | import instock.core.backtest.rate_stats as rate
18 | from instock.core.singleton_stock import stock_hist_data
19 |
20 | __author__ = 'myh '
21 | __date__ = '2023/3/10 '
22 |
23 |
24 | # 股票策略回归测试。
25 | def prepare():
26 | tables = [tbs.TABLE_CN_STOCK_INDICATORS_BUY, tbs.TABLE_CN_STOCK_INDICATORS_SELL]
27 | tables.extend(tbs.TABLE_CN_STOCK_STRATEGIES)
28 | backtest_columns = list(tbs.TABLE_CN_STOCK_BACKTEST_DATA['columns'])
29 | backtest_columns.insert(0, 'code')
30 | backtest_columns.insert(0, 'date')
31 | backtest_column = backtest_columns
32 |
33 | stocks_data = stock_hist_data().get_data()
34 | if stocks_data is None:
35 | return
36 | for k in stocks_data:
37 | date = k[0]
38 | break
39 | # 回归测试表
40 | with concurrent.futures.ThreadPoolExecutor() as executor:
41 | for table in tables:
42 | executor.submit(process, table, stocks_data, date, backtest_column)
43 |
44 |
45 | def process(table, data_all, date, backtest_column):
46 | table_name = table['name']
47 | if not mdb.checkTableIsExist(table_name):
48 | return
49 |
50 | column_tail = tuple(table['columns'])[-1]
51 | now_date = datetime.datetime.now().date()
52 | sql = f"SELECT * FROM `{table_name}` WHERE `date` < '{now_date}' AND `{column_tail}` is NULL"
53 | try:
54 | data = pd.read_sql(sql=sql, con=mdb.engine())
55 | if data is None or len(data.index) == 0:
56 | return
57 |
58 | subset = data[list(tbs.TABLE_CN_STOCK_FOREIGN_KEY['columns'])]
59 | # subset['date'] = subset['date'].values.astype('str')
60 | subset = subset.astype({'date': 'string'})
61 | stocks = [tuple(x) for x in subset.values]
62 |
63 | results = run_check(stocks, data_all, date, backtest_column)
64 | if results is None:
65 | return
66 |
67 | data_new = pd.DataFrame(results.values())
68 | mdb.update_db_from_df(data_new, table_name, ('date', 'code'))
69 |
70 | except Exception as e:
71 | logging.error(f"backtest_data_daily_job.process处理异常:{table}表{e}")
72 |
73 |
74 | def run_check(stocks, data_all, date, backtest_column, workers=40):
75 | data = {}
76 | try:
77 | with concurrent.futures.ThreadPoolExecutor(max_workers=workers) as executor:
78 | future_to_data = {executor.submit(rate.get_rates, stock,
79 | data_all.get((date, stock[1], stock[2])), backtest_column,
80 | len(backtest_column) - 1): stock for stock in stocks}
81 | for future in concurrent.futures.as_completed(future_to_data):
82 | stock = future_to_data[future]
83 | try:
84 | _data_ = future.result()
85 | if _data_ is not None:
86 | data[stock] = _data_
87 | except Exception as e:
88 | logging.error(f"backtest_data_daily_job.run_check处理异常:{stock[1]}代码{e}")
89 | except Exception as e:
90 | logging.error(f"backtest_data_daily_job.run_check处理异常:{e}")
91 | if not data:
92 | return None
93 | else:
94 | return data
95 |
96 |
97 | def main():
98 | prepare()
99 |
100 |
101 | # main函数入口
102 | if __name__ == '__main__':
103 | main()
104 |
--------------------------------------------------------------------------------
/docker/.gitignore:
--------------------------------------------------------------------------------
1 | # Byte-compiled / optimized / DLL files
2 | __pycache__/
3 | *.py[cod]
4 | *$py.class
5 |
6 | # C extensions
7 | *.so
8 |
9 | # Distribution / packaging
10 | .Python
11 | build/
12 | develop-eggs/
13 | dist/
14 | downloads/
15 | eggs/
16 | .eggs/
17 | parts/
18 | sdist/
19 | var/
20 | wheels/
21 | share/python-wheels/
22 | *.egg-info/
23 | .installed.cfg
24 | *.egg
25 | MANIFEST
26 |
27 | # PyInstaller
28 | # Usually these files are written by a python script from a template
29 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
30 | *.manifest
31 | *.spec
32 |
33 | # Installer logs
34 | pip-log.txt
35 | pip-delete-this-directory.txt
36 |
37 | # Unit test / coverage reports
38 | htmlcov/
39 | .tox/
40 | .nox/
41 | .coverage
42 | .coverage.*
43 | .cache
44 | nosetests.xml
45 | coverage.xml
46 | *.cover
47 | *.py,cover
48 | .hypothesis/
49 | .pytest_cache/
50 | cover/
51 |
52 | # Translations
53 | *.mo
54 | *.pot
55 |
56 | # Django stuff:
57 | *.log
58 | local_settings.py
59 | db.sqlite3
60 | db.sqlite3-journal
61 |
62 | # Flask stuff:
63 | instance/
64 | .webassets-cache
65 |
66 | # Scrapy stuff:
67 | .scrapy
68 |
69 | # Sphinx documentation
70 | docs/_build/
71 |
72 | # PyBuilder
73 | .pybuilder/
74 | target/
75 |
76 | # Jupyter Notebook
77 | .ipynb_checkpoints
78 |
79 | # IPython
80 | profile_default/
81 | ipython_config.py
82 |
83 | # pyenv
84 | # For a library or package, you might want to ignore these files since the code is
85 | # intended to run in multiple environments; otherwise, check them in:
86 | # .python-version
87 |
88 | # pipenv
89 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
90 | # However, in case of collaboration, if having platform-specific dependencies or dependencies
91 | # having no cross-platform support, pipenv may install dependencies that don't work, or not
92 | # install all needed dependencies.
93 | #Pipfile.lock
94 |
95 | # poetry
96 | # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
97 | # This is especially recommended for binary packages to ensure reproducibility, and is more
98 | # commonly ignored for libraries.
99 | # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
100 | #poetry.lock
101 |
102 | # pdm
103 | # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
104 | #pdm.lock
105 | # pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
106 | # in version control.
107 | # https://pdm.fming.dev/#use-with-ide
108 | .pdm.toml
109 |
110 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
111 | __pypackages__/
112 |
113 | # Celery stuff
114 | celerybeat-schedule
115 | celerybeat.pid
116 |
117 | # SageMath parsed files
118 | *.sage.py
119 |
120 | # Environments
121 | .env
122 | .venv
123 | env/
124 | venv/
125 | ENV/
126 | env.bak/
127 | venv.bak/
128 |
129 | # Spyder project settings
130 | .spyderproject
131 | .spyproject
132 |
133 | # Rope project settings
134 | .ropeproject
135 |
136 | # mkdocs documentation
137 | /site
138 |
139 | # mypy
140 | .mypy_cache/
141 | .dmypy.json
142 | dmypy.json
143 |
144 | # Pyre type checker
145 | .pyre/
146 |
147 | # pytype static type analyzer
148 | .pytype/
149 |
150 | # Cython debug symbols
151 | cython_debug/
152 |
153 | # PyCharm
154 | # JetBrains specific template is maintained in a separate JetBrains.gitignore that can
155 | # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
156 | # and can be added to the global gitignore or merged into this file. For a more nuclear
157 | # option (not recommended) you can uncomment the following to ignore the entire idea folder.
158 | .idea/
159 |
160 | docker.*
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Byte-compiled / optimized / DLL files
2 | __pycache__/
3 | *.py[cod]
4 | *$py.class
5 |
6 | # C extensions
7 | *.so
8 |
9 | # Distribution / packaging
10 | .Python
11 | build/
12 | develop-eggs/
13 | dist/
14 | downloads/
15 | eggs/
16 | .eggs/
17 | parts/
18 | sdist/
19 | var/
20 | wheels/
21 | share/python-wheels/
22 | *.egg-info/
23 | .installed.cfg
24 | *.egg
25 | MANIFEST
26 |
27 | # PyInstaller
28 | # Usually these files are written by a python script from a template
29 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
30 | *.manifest
31 | *.spec
32 |
33 | # Installer logs
34 | pip-log.txt
35 | pip-delete-this-directory.txt
36 |
37 | # Unit test / coverage reports
38 | htmlcov/
39 | .tox/
40 | .nox/
41 | .coverage
42 | .coverage.*
43 | .cache
44 | nosetests.xml
45 | coverage.xml
46 | *.cover
47 | *.py,cover
48 | .hypothesis/
49 | .pytest_cache/
50 | cover/
51 |
52 | # Translations
53 | *.mo
54 | *.pot
55 |
56 | # Django stuff:
57 | *.log
58 | local_settings.py
59 | db.sqlite3
60 | db.sqlite3-journal
61 |
62 | # Flask stuff:
63 | instance/
64 | .webassets-cache
65 |
66 | # Scrapy stuff:
67 | .scrapy
68 |
69 | # Sphinx documentation
70 | docs/_build/
71 |
72 | # PyBuilder
73 | .pybuilder/
74 | target/
75 |
76 | # Jupyter Notebook
77 | .ipynb_checkpoints
78 |
79 | # IPython
80 | profile_default/
81 | ipython_config.py
82 |
83 | # pyenv
84 | # For a library or package, you might want to ignore these files since the code is
85 | # intended to run in multiple environments; otherwise, check them in:
86 | # .python-version
87 |
88 | # pipenv
89 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
90 | # However, in case of collaboration, if having platform-specific dependencies or dependencies
91 | # having no cross-platform support, pipenv may install dependencies that don't work, or not
92 | # install all needed dependencies.
93 | #Pipfile.lock
94 |
95 | # poetry
96 | # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
97 | # This is especially recommended for binary packages to ensure reproducibility, and is more
98 | # commonly ignored for libraries.
99 | # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
100 | #poetry.lock
101 |
102 | # pdm
103 | # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
104 | #pdm.lock
105 | # pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
106 | # in version control.
107 | # https://pdm.fming.dev/#use-with-ide
108 | .pdm.toml
109 |
110 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
111 | __pypackages__/
112 |
113 | # Celery stuff
114 | celerybeat-schedule
115 | celerybeat.pid
116 |
117 | # SageMath parsed files
118 | *.sage.py
119 |
120 | # Environments
121 | .env
122 | .venv
123 | env/
124 | venv/
125 | ENV/
126 | env.bak/
127 | venv.bak/
128 |
129 | # Spyder project settings
130 | .spyderproject
131 | .spyproject
132 |
133 | # Rope project settings
134 | .ropeproject
135 |
136 | # mkdocs documentation
137 | /site
138 |
139 | # mypy
140 | .mypy_cache/
141 | .dmypy.json
142 | dmypy.json
143 |
144 | # Pyre type checker
145 | .pyre/
146 |
147 | # pytype static type analyzer
148 | .pytype/
149 |
150 | # Cython debug symbols
151 | cython_debug/
152 |
153 | # PyCharm
154 | # JetBrains specific template is maintained in a separate JetBrains.gitignore that can
155 | # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
156 | # and can be added to the global gitignore or merged into this file. For a more nuclear
157 | # option (not recommended) you can uncomment the following to ignore the entire idea folder.
158 | .idea/
159 |
160 | cache/
161 | log/
162 | test/
--------------------------------------------------------------------------------
/instock/core/.gitignore:
--------------------------------------------------------------------------------
1 | # Byte-compiled / optimized / DLL files
2 | __pycache__/
3 | *.py[cod]
4 | *$py.class
5 |
6 | # C extensions
7 | *.so
8 |
9 | # Distribution / packaging
10 | .Python
11 | build/
12 | develop-eggs/
13 | dist/
14 | downloads/
15 | eggs/
16 | .eggs/
17 | lib/
18 | lib64/
19 | parts/
20 | sdist/
21 | var/
22 | wheels/
23 | share/python-wheels/
24 | *.egg-info/
25 | .installed.cfg
26 | *.egg
27 | MANIFEST
28 |
29 | # PyInstaller
30 | # Usually these files are written by a python script from a template
31 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
32 | *.manifest
33 | *.spec
34 |
35 | # Installer logs
36 | pip-log.txt
37 | pip-delete-this-directory.txt
38 |
39 | # Unit test / coverage reports
40 | htmlcov/
41 | .tox/
42 | .nox/
43 | .coverage
44 | .coverage.*
45 | .cache
46 | nosetests.xml
47 | coverage.xml
48 | *.cover
49 | *.py,cover
50 | .hypothesis/
51 | .pytest_cache/
52 | cover/
53 |
54 | # Translations
55 | *.mo
56 | *.pot
57 |
58 | # Django stuff:
59 | *.log
60 | local_settings.py
61 | db.sqlite3
62 | db.sqlite3-journal
63 |
64 | # Flask stuff:
65 | instance/
66 | .webassets-cache
67 |
68 | # Scrapy stuff:
69 | .scrapy
70 |
71 | # Sphinx documentation
72 | docs/_build/
73 |
74 | # PyBuilder
75 | .pybuilder/
76 | target/
77 |
78 | # Jupyter Notebook
79 | .ipynb_checkpoints
80 |
81 | # IPython
82 | profile_default/
83 | ipython_config.py
84 |
85 | # pyenv
86 | # For a library or package, you might want to ignore these files since the code is
87 | # intended to run in multiple environments; otherwise, check them in:
88 | # .python-version
89 |
90 | # pipenv
91 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
92 | # However, in case of collaboration, if having platform-specific dependencies or dependencies
93 | # having no cross-platform support, pipenv may install dependencies that don't work, or not
94 | # install all needed dependencies.
95 | #Pipfile.lock
96 |
97 | # poetry
98 | # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
99 | # This is especially recommended for binary packages to ensure reproducibility, and is more
100 | # commonly ignored for libraries.
101 | # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
102 | #poetry.lock
103 |
104 | # pdm
105 | # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
106 | #pdm.lock
107 | # pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
108 | # in version control.
109 | # https://pdm.fming.dev/#use-with-ide
110 | .pdm.toml
111 |
112 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
113 | __pypackages__/
114 |
115 | # Celery stuff
116 | celerybeat-schedule
117 | celerybeat.pid
118 |
119 | # SageMath parsed files
120 | *.sage.py
121 |
122 | # Environments
123 | .env
124 | .venv
125 | env/
126 | venv/
127 | ENV/
128 | env.bak/
129 | venv.bak/
130 |
131 | # Spyder project settings
132 | .spyderproject
133 | .spyproject
134 |
135 | # Rope project settings
136 | .ropeproject
137 |
138 | # mkdocs documentation
139 | /site
140 |
141 | # mypy
142 | .mypy_cache/
143 | .dmypy.json
144 | dmypy.json
145 |
146 | # Pyre type checker
147 | .pyre/
148 |
149 | # pytype static type analyzer
150 | .pytype/
151 |
152 | # Cython debug symbols
153 | cython_debug/
154 |
155 | # PyCharm
156 | # JetBrains specific template is maintained in a separate JetBrains.gitignore that can
157 | # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
158 | # and can be added to the global gitignore or merged into this file. For a more nuclear
159 | # option (not recommended) you can uncomment the following to ignore the entire idea folder.
160 | .idea/
161 |
--------------------------------------------------------------------------------
/instock/job/.gitignore:
--------------------------------------------------------------------------------
1 | # Byte-compiled / optimized / DLL files
2 | __pycache__/
3 | *.py[cod]
4 | *$py.class
5 |
6 | # C extensions
7 | *.so
8 |
9 | # Distribution / packaging
10 | .Python
11 | build/
12 | develop-eggs/
13 | dist/
14 | downloads/
15 | eggs/
16 | .eggs/
17 | lib/
18 | lib64/
19 | parts/
20 | sdist/
21 | var/
22 | wheels/
23 | share/python-wheels/
24 | *.egg-info/
25 | .installed.cfg
26 | *.egg
27 | MANIFEST
28 |
29 | # PyInstaller
30 | # Usually these files are written by a python script from a template
31 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
32 | *.manifest
33 | *.spec
34 |
35 | # Installer logs
36 | pip-log.txt
37 | pip-delete-this-directory.txt
38 |
39 | # Unit test / coverage reports
40 | htmlcov/
41 | .tox/
42 | .nox/
43 | .coverage
44 | .coverage.*
45 | .cache
46 | nosetests.xml
47 | coverage.xml
48 | *.cover
49 | *.py,cover
50 | .hypothesis/
51 | .pytest_cache/
52 | cover/
53 |
54 | # Translations
55 | *.mo
56 | *.pot
57 |
58 | # Django stuff:
59 | *.log
60 | local_settings.py
61 | db.sqlite3
62 | db.sqlite3-journal
63 |
64 | # Flask stuff:
65 | instance/
66 | .webassets-cache
67 |
68 | # Scrapy stuff:
69 | .scrapy
70 |
71 | # Sphinx documentation
72 | docs/_build/
73 |
74 | # PyBuilder
75 | .pybuilder/
76 | target/
77 |
78 | # Jupyter Notebook
79 | .ipynb_checkpoints
80 |
81 | # IPython
82 | profile_default/
83 | ipython_config.py
84 |
85 | # pyenv
86 | # For a library or package, you might want to ignore these files since the code is
87 | # intended to run in multiple environments; otherwise, check them in:
88 | # .python-version
89 |
90 | # pipenv
91 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
92 | # However, in case of collaboration, if having platform-specific dependencies or dependencies
93 | # having no cross-platform support, pipenv may install dependencies that don't work, or not
94 | # install all needed dependencies.
95 | #Pipfile.lock
96 |
97 | # poetry
98 | # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
99 | # This is especially recommended for binary packages to ensure reproducibility, and is more
100 | # commonly ignored for libraries.
101 | # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
102 | #poetry.lock
103 |
104 | # pdm
105 | # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
106 | #pdm.lock
107 | # pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
108 | # in version control.
109 | # https://pdm.fming.dev/#use-with-ide
110 | .pdm.toml
111 |
112 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
113 | __pypackages__/
114 |
115 | # Celery stuff
116 | celerybeat-schedule
117 | celerybeat.pid
118 |
119 | # SageMath parsed files
120 | *.sage.py
121 |
122 | # Environments
123 | .env
124 | .venv
125 | env/
126 | venv/
127 | ENV/
128 | env.bak/
129 | venv.bak/
130 |
131 | # Spyder project settings
132 | .spyderproject
133 | .spyproject
134 |
135 | # Rope project settings
136 | .ropeproject
137 |
138 | # mkdocs documentation
139 | /site
140 |
141 | # mypy
142 | .mypy_cache/
143 | .dmypy.json
144 | dmypy.json
145 |
146 | # Pyre type checker
147 | .pyre/
148 |
149 | # pytype static type analyzer
150 | .pytype/
151 |
152 | # Cython debug symbols
153 | cython_debug/
154 |
155 | # PyCharm
156 | # JetBrains specific template is maintained in a separate JetBrains.gitignore that can
157 | # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
158 | # and can be added to the global gitignore or merged into this file. For a more nuclear
159 | # option (not recommended) you can uncomment the following to ignore the entire idea folder.
160 | .idea/
161 |
--------------------------------------------------------------------------------
/instock/lib/.gitignore:
--------------------------------------------------------------------------------
1 | # Byte-compiled / optimized / DLL files
2 | __pycache__/
3 | *.py[cod]
4 | *$py.class
5 |
6 | # C extensions
7 | *.so
8 |
9 | # Distribution / packaging
10 | .Python
11 | build/
12 | develop-eggs/
13 | dist/
14 | downloads/
15 | eggs/
16 | .eggs/
17 | lib/
18 | lib64/
19 | parts/
20 | sdist/
21 | var/
22 | wheels/
23 | share/python-wheels/
24 | *.egg-info/
25 | .installed.cfg
26 | *.egg
27 | MANIFEST
28 |
29 | # PyInstaller
30 | # Usually these files are written by a python script from a template
31 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
32 | *.manifest
33 | *.spec
34 |
35 | # Installer logs
36 | pip-log.txt
37 | pip-delete-this-directory.txt
38 |
39 | # Unit test / coverage reports
40 | htmlcov/
41 | .tox/
42 | .nox/
43 | .coverage
44 | .coverage.*
45 | .cache
46 | nosetests.xml
47 | coverage.xml
48 | *.cover
49 | *.py,cover
50 | .hypothesis/
51 | .pytest_cache/
52 | cover/
53 |
54 | # Translations
55 | *.mo
56 | *.pot
57 |
58 | # Django stuff:
59 | *.log
60 | local_settings.py
61 | db.sqlite3
62 | db.sqlite3-journal
63 |
64 | # Flask stuff:
65 | instance/
66 | .webassets-cache
67 |
68 | # Scrapy stuff:
69 | .scrapy
70 |
71 | # Sphinx documentation
72 | docs/_build/
73 |
74 | # PyBuilder
75 | .pybuilder/
76 | target/
77 |
78 | # Jupyter Notebook
79 | .ipynb_checkpoints
80 |
81 | # IPython
82 | profile_default/
83 | ipython_config.py
84 |
85 | # pyenv
86 | # For a library or package, you might want to ignore these files since the code is
87 | # intended to run in multiple environments; otherwise, check them in:
88 | # .python-version
89 |
90 | # pipenv
91 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
92 | # However, in case of collaboration, if having platform-specific dependencies or dependencies
93 | # having no cross-platform support, pipenv may install dependencies that don't work, or not
94 | # install all needed dependencies.
95 | #Pipfile.lock
96 |
97 | # poetry
98 | # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
99 | # This is especially recommended for binary packages to ensure reproducibility, and is more
100 | # commonly ignored for libraries.
101 | # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
102 | #poetry.lock
103 |
104 | # pdm
105 | # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
106 | #pdm.lock
107 | # pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
108 | # in version control.
109 | # https://pdm.fming.dev/#use-with-ide
110 | .pdm.toml
111 |
112 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
113 | __pypackages__/
114 |
115 | # Celery stuff
116 | celerybeat-schedule
117 | celerybeat.pid
118 |
119 | # SageMath parsed files
120 | *.sage.py
121 |
122 | # Environments
123 | .env
124 | .venv
125 | env/
126 | venv/
127 | ENV/
128 | env.bak/
129 | venv.bak/
130 |
131 | # Spyder project settings
132 | .spyderproject
133 | .spyproject
134 |
135 | # Rope project settings
136 | .ropeproject
137 |
138 | # mkdocs documentation
139 | /site
140 |
141 | # mypy
142 | .mypy_cache/
143 | .dmypy.json
144 | dmypy.json
145 |
146 | # Pyre type checker
147 | .pyre/
148 |
149 | # pytype static type analyzer
150 | .pytype/
151 |
152 | # Cython debug symbols
153 | cython_debug/
154 |
155 | # PyCharm
156 | # JetBrains specific template is maintained in a separate JetBrains.gitignore that can
157 | # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
158 | # and can be added to the global gitignore or merged into this file. For a more nuclear
159 | # option (not recommended) you can uncomment the following to ignore the entire idea folder.
160 | .idea/
161 |
--------------------------------------------------------------------------------
/instock/trade/.gitignore:
--------------------------------------------------------------------------------
1 | # Byte-compiled / optimized / DLL files
2 | __pycache__/
3 | *.py[cod]
4 | *$py.class
5 |
6 | # C extensions
7 | *.so
8 |
9 | # Distribution / packaging
10 | .Python
11 | build/
12 | develop-eggs/
13 | dist/
14 | downloads/
15 | eggs/
16 | .eggs/
17 | lib/
18 | lib64/
19 | parts/
20 | sdist/
21 | var/
22 | wheels/
23 | share/python-wheels/
24 | *.egg-info/
25 | .installed.cfg
26 | *.egg
27 | MANIFEST
28 |
29 | # PyInstaller
30 | # Usually these files are written by a python script from a template
31 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
32 | *.manifest
33 | *.spec
34 |
35 | # Installer logs
36 | pip-log.txt
37 | pip-delete-this-directory.txt
38 |
39 | # Unit test / coverage reports
40 | htmlcov/
41 | .tox/
42 | .nox/
43 | .coverage
44 | .coverage.*
45 | .cache
46 | nosetests.xml
47 | coverage.xml
48 | *.cover
49 | *.py,cover
50 | .hypothesis/
51 | .pytest_cache/
52 | cover/
53 |
54 | # Translations
55 | *.mo
56 | *.pot
57 |
58 | # Django stuff:
59 | *.log
60 | local_settings.py
61 | db.sqlite3
62 | db.sqlite3-journal
63 |
64 | # Flask stuff:
65 | instance/
66 | .webassets-cache
67 |
68 | # Scrapy stuff:
69 | .scrapy
70 |
71 | # Sphinx documentation
72 | docs/_build/
73 |
74 | # PyBuilder
75 | .pybuilder/
76 | target/
77 |
78 | # Jupyter Notebook
79 | .ipynb_checkpoints
80 |
81 | # IPython
82 | profile_default/
83 | ipython_config.py
84 |
85 | # pyenv
86 | # For a library or package, you might want to ignore these files since the code is
87 | # intended to run in multiple environments; otherwise, check them in:
88 | # .python-version
89 |
90 | # pipenv
91 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
92 | # However, in case of collaboration, if having platform-specific dependencies or dependencies
93 | # having no cross-platform support, pipenv may install dependencies that don't work, or not
94 | # install all needed dependencies.
95 | #Pipfile.lock
96 |
97 | # poetry
98 | # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
99 | # This is especially recommended for binary packages to ensure reproducibility, and is more
100 | # commonly ignored for libraries.
101 | # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
102 | #poetry.lock
103 |
104 | # pdm
105 | # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
106 | #pdm.lock
107 | # pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
108 | # in version control.
109 | # https://pdm.fming.dev/#use-with-ide
110 | .pdm.toml
111 |
112 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
113 | __pypackages__/
114 |
115 | # Celery stuff
116 | celerybeat-schedule
117 | celerybeat.pid
118 |
119 | # SageMath parsed files
120 | *.sage.py
121 |
122 | # Environments
123 | .env
124 | .venv
125 | env/
126 | venv/
127 | ENV/
128 | env.bak/
129 | venv.bak/
130 |
131 | # Spyder project settings
132 | .spyderproject
133 | .spyproject
134 |
135 | # Rope project settings
136 | .ropeproject
137 |
138 | # mkdocs documentation
139 | /site
140 |
141 | # mypy
142 | .mypy_cache/
143 | .dmypy.json
144 | dmypy.json
145 |
146 | # Pyre type checker
147 | .pyre/
148 |
149 | # pytype static type analyzer
150 | .pytype/
151 |
152 | # Cython debug symbols
153 | cython_debug/
154 |
155 | # PyCharm
156 | # JetBrains specific template is maintained in a separate JetBrains.gitignore that can
157 | # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
158 | # and can be added to the global gitignore or merged into this file. For a more nuclear
159 | # option (not recommended) you can uncomment the following to ignore the entire idea folder.
160 | .idea/
161 |
--------------------------------------------------------------------------------
/instock/web/.gitignore:
--------------------------------------------------------------------------------
1 | # Byte-compiled / optimized / DLL files
2 | __pycache__/
3 | *.py[cod]
4 | *$py.class
5 |
6 | # C extensions
7 | *.so
8 |
9 | # Distribution / packaging
10 | .Python
11 | build/
12 | develop-eggs/
13 | dist/
14 | downloads/
15 | eggs/
16 | .eggs/
17 | lib/
18 | lib64/
19 | parts/
20 | sdist/
21 | var/
22 | wheels/
23 | share/python-wheels/
24 | *.egg-info/
25 | .installed.cfg
26 | *.egg
27 | MANIFEST
28 |
29 | # PyInstaller
30 | # Usually these files are written by a python script from a template
31 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
32 | *.manifest
33 | *.spec
34 |
35 | # Installer logs
36 | pip-log.txt
37 | pip-delete-this-directory.txt
38 |
39 | # Unit test / coverage reports
40 | htmlcov/
41 | .tox/
42 | .nox/
43 | .coverage
44 | .coverage.*
45 | .cache
46 | nosetests.xml
47 | coverage.xml
48 | *.cover
49 | *.py,cover
50 | .hypothesis/
51 | .pytest_cache/
52 | cover/
53 |
54 | # Translations
55 | *.mo
56 | *.pot
57 |
58 | # Django stuff:
59 | *.log
60 | local_settings.py
61 | db.sqlite3
62 | db.sqlite3-journal
63 |
64 | # Flask stuff:
65 | instance/
66 | .webassets-cache
67 |
68 | # Scrapy stuff:
69 | .scrapy
70 |
71 | # Sphinx documentation
72 | docs/_build/
73 |
74 | # PyBuilder
75 | .pybuilder/
76 | target/
77 |
78 | # Jupyter Notebook
79 | .ipynb_checkpoints
80 |
81 | # IPython
82 | profile_default/
83 | ipython_config.py
84 |
85 | # pyenv
86 | # For a library or package, you might want to ignore these files since the code is
87 | # intended to run in multiple environments; otherwise, check them in:
88 | # .python-version
89 |
90 | # pipenv
91 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
92 | # However, in case of collaboration, if having platform-specific dependencies or dependencies
93 | # having no cross-platform support, pipenv may install dependencies that don't work, or not
94 | # install all needed dependencies.
95 | #Pipfile.lock
96 |
97 | # poetry
98 | # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
99 | # This is especially recommended for binary packages to ensure reproducibility, and is more
100 | # commonly ignored for libraries.
101 | # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
102 | #poetry.lock
103 |
104 | # pdm
105 | # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
106 | #pdm.lock
107 | # pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
108 | # in version control.
109 | # https://pdm.fming.dev/#use-with-ide
110 | .pdm.toml
111 |
112 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
113 | __pypackages__/
114 |
115 | # Celery stuff
116 | celerybeat-schedule
117 | celerybeat.pid
118 |
119 | # SageMath parsed files
120 | *.sage.py
121 |
122 | # Environments
123 | .env
124 | .venv
125 | env/
126 | venv/
127 | ENV/
128 | env.bak/
129 | venv.bak/
130 |
131 | # Spyder project settings
132 | .spyderproject
133 | .spyproject
134 |
135 | # Rope project settings
136 | .ropeproject
137 |
138 | # mkdocs documentation
139 | /site
140 |
141 | # mypy
142 | .mypy_cache/
143 | .dmypy.json
144 | dmypy.json
145 |
146 | # Pyre type checker
147 | .pyre/
148 |
149 | # pytype static type analyzer
150 | .pytype/
151 |
152 | # Cython debug symbols
153 | cython_debug/
154 |
155 | # PyCharm
156 | # JetBrains specific template is maintained in a separate JetBrains.gitignore that can
157 | # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
158 | # and can be added to the global gitignore or merged into this file. For a more nuclear
159 | # option (not recommended) you can uncomment the following to ignore the entire idea folder.
160 | .idea/
161 |
--------------------------------------------------------------------------------
/instock/config/.gitignore:
--------------------------------------------------------------------------------
1 | # Byte-compiled / optimized / DLL files
2 | __pycache__/
3 | *.py[cod]
4 | *$py.class
5 |
6 | # C extensions
7 | *.so
8 |
9 | # Distribution / packaging
10 | .Python
11 | build/
12 | develop-eggs/
13 | dist/
14 | downloads/
15 | eggs/
16 | .eggs/
17 | parts/
18 | sdist/
19 | var/
20 | wheels/
21 | share/python-wheels/
22 | *.egg-info/
23 | .installed.cfg
24 | *.egg
25 | MANIFEST
26 |
27 | # PyInstaller
28 | # Usually these files are written by a python script from a template
29 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
30 | *.manifest
31 | *.spec
32 |
33 | # Installer logs
34 | pip-log.txt
35 | pip-delete-this-directory.txt
36 |
37 | # Unit test / coverage reports
38 | htmlcov/
39 | .tox/
40 | .nox/
41 | .coverage
42 | .coverage.*
43 | .cache
44 | nosetests.xml
45 | coverage.xml
46 | *.cover
47 | *.py,cover
48 | .hypothesis/
49 | .pytest_cache/
50 | cover/
51 |
52 | # Translations
53 | *.mo
54 | *.pot
55 |
56 | # Django stuff:
57 | *.log
58 | local_settings.py
59 | db.sqlite3
60 | db.sqlite3-journal
61 |
62 | # Flask stuff:
63 | instance/
64 | .webassets-cache
65 |
66 | # Scrapy stuff:
67 | .scrapy
68 |
69 | # Sphinx documentation
70 | docs/_build/
71 |
72 | # PyBuilder
73 | .pybuilder/
74 | target/
75 |
76 | # Jupyter Notebook
77 | .ipynb_checkpoints
78 |
79 | # IPython
80 | profile_default/
81 | ipython_config.py
82 |
83 | # pyenv
84 | # For a library or package, you might want to ignore these files since the code is
85 | # intended to run in multiple environments; otherwise, check them in:
86 | # .python-version
87 |
88 | # pipenv
89 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
90 | # However, in case of collaboration, if having platform-specific dependencies or dependencies
91 | # having no cross-platform support, pipenv may install dependencies that don't work, or not
92 | # install all needed dependencies.
93 | #Pipfile.lock
94 |
95 | # poetry
96 | # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
97 | # This is especially recommended for binary packages to ensure reproducibility, and is more
98 | # commonly ignored for libraries.
99 | # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
100 | #poetry.lock
101 |
102 | # pdm
103 | # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
104 | #pdm.lock
105 | # pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
106 | # in version control.
107 | # https://pdm.fming.dev/#use-with-ide
108 | .pdm.toml
109 |
110 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
111 | __pypackages__/
112 |
113 | # Celery stuff
114 | celerybeat-schedule
115 | celerybeat.pid
116 |
117 | # SageMath parsed files
118 | *.sage.py
119 |
120 | # Environments
121 | .env
122 | .venv
123 | env/
124 | venv/
125 | ENV/
126 | env.bak/
127 | venv.bak/
128 |
129 | # Spyder project settings
130 | .spyderproject
131 | .spyproject
132 |
133 | # Rope project settings
134 | .ropeproject
135 |
136 | # mkdocs documentation
137 | /site
138 |
139 | # mypy
140 | .mypy_cache/
141 | .dmypy.json
142 | dmypy.json
143 |
144 | # Pyre type checker
145 | .pyre/
146 |
147 | # pytype static type analyzer
148 | .pytype/
149 |
150 | # Cython debug symbols
151 | cython_debug/
152 |
153 | # PyCharm
154 | # JetBrains specific template is maintained in a separate JetBrains.gitignore that can
155 | # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
156 | # and can be added to the global gitignore or merged into this file. For a more nuclear
157 | # option (not recommended) you can uncomment the following to ignore the entire idea folder.
158 | .idea/
159 |
160 | gf_client.json
161 |
--------------------------------------------------------------------------------
/instock/core/kline/.gitignore:
--------------------------------------------------------------------------------
1 | # Byte-compiled / optimized / DLL files
2 | __pycache__/
3 | *.py[cod]
4 | *$py.class
5 |
6 | # C extensions
7 | *.so
8 |
9 | # Distribution / packaging
10 | .Python
11 | build/
12 | develop-eggs/
13 | dist/
14 | downloads/
15 | eggs/
16 | .eggs/
17 | lib/
18 | lib64/
19 | parts/
20 | sdist/
21 | var/
22 | wheels/
23 | share/python-wheels/
24 | *.egg-info/
25 | .installed.cfg
26 | *.egg
27 | MANIFEST
28 |
29 | # PyInstaller
30 | # Usually these files are written by a python script from a template
31 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
32 | *.manifest
33 | *.spec
34 |
35 | # Installer logs
36 | pip-log.txt
37 | pip-delete-this-directory.txt
38 |
39 | # Unit test / coverage reports
40 | htmlcov/
41 | .tox/
42 | .nox/
43 | .coverage
44 | .coverage.*
45 | .cache
46 | nosetests.xml
47 | coverage.xml
48 | *.cover
49 | *.py,cover
50 | .hypothesis/
51 | .pytest_cache/
52 | cover/
53 |
54 | # Translations
55 | *.mo
56 | *.pot
57 |
58 | # Django stuff:
59 | *.log
60 | local_settings.py
61 | db.sqlite3
62 | db.sqlite3-journal
63 |
64 | # Flask stuff:
65 | instance/
66 | .webassets-cache
67 |
68 | # Scrapy stuff:
69 | .scrapy
70 |
71 | # Sphinx documentation
72 | docs/_build/
73 |
74 | # PyBuilder
75 | .pybuilder/
76 | target/
77 |
78 | # Jupyter Notebook
79 | .ipynb_checkpoints
80 |
81 | # IPython
82 | profile_default/
83 | ipython_config.py
84 |
85 | # pyenv
86 | # For a library or package, you might want to ignore these files since the code is
87 | # intended to run in multiple environments; otherwise, check them in:
88 | # .python-version
89 |
90 | # pipenv
91 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
92 | # However, in case of collaboration, if having platform-specific dependencies or dependencies
93 | # having no cross-platform support, pipenv may install dependencies that don't work, or not
94 | # install all needed dependencies.
95 | #Pipfile.lock
96 |
97 | # poetry
98 | # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
99 | # This is especially recommended for binary packages to ensure reproducibility, and is more
100 | # commonly ignored for libraries.
101 | # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
102 | #poetry.lock
103 |
104 | # pdm
105 | # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
106 | #pdm.lock
107 | # pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
108 | # in version control.
109 | # https://pdm.fming.dev/#use-with-ide
110 | .pdm.toml
111 |
112 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
113 | __pypackages__/
114 |
115 | # Celery stuff
116 | celerybeat-schedule
117 | celerybeat.pid
118 |
119 | # SageMath parsed files
120 | *.sage.py
121 |
122 | # Environments
123 | .env
124 | .venv
125 | env/
126 | venv/
127 | ENV/
128 | env.bak/
129 | venv.bak/
130 |
131 | # Spyder project settings
132 | .spyderproject
133 | .spyproject
134 |
135 | # Rope project settings
136 | .ropeproject
137 |
138 | # mkdocs documentation
139 | /site
140 |
141 | # mypy
142 | .mypy_cache/
143 | .dmypy.json
144 | dmypy.json
145 |
146 | # Pyre type checker
147 | .pyre/
148 |
149 | # pytype static type analyzer
150 | .pytype/
151 |
152 | # Cython debug symbols
153 | cython_debug/
154 |
155 | # PyCharm
156 | # JetBrains specific template is maintained in a separate JetBrains.gitignore that can
157 | # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
158 | # and can be added to the global gitignore or merged into this file. For a more nuclear
159 | # option (not recommended) you can uncomment the following to ignore the entire idea folder.
160 | .idea/
161 |
--------------------------------------------------------------------------------
/instock/.gitignore:
--------------------------------------------------------------------------------
1 | # Byte-compiled / optimized / DLL files
2 | __pycache__/
3 | *.py[cod]
4 | *$py.class
5 |
6 | # C extensions
7 | *.so
8 |
9 | # Distribution / packaging
10 | .Python
11 | build/
12 | develop-eggs/
13 | dist/
14 | downloads/
15 | eggs/
16 | .eggs/
17 | parts/
18 | sdist/
19 | var/
20 | wheels/
21 | share/python-wheels/
22 | *.egg-info/
23 | .installed.cfg
24 | *.egg
25 | MANIFEST
26 |
27 | # PyInstaller
28 | # Usually these files are written by a python script from a template
29 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
30 | *.manifest
31 | *.spec
32 |
33 | # Installer logs
34 | pip-log.txt
35 | pip-delete-this-directory.txt
36 |
37 | # Unit test / coverage reports
38 | htmlcov/
39 | .tox/
40 | .nox/
41 | .coverage
42 | .coverage.*
43 | .cache
44 | nosetests.xml
45 | coverage.xml
46 | *.cover
47 | *.py,cover
48 | .hypothesis/
49 | .pytest_cache/
50 | cover/
51 |
52 | # Translations
53 | *.mo
54 | *.pot
55 |
56 | # Django stuff:
57 | *.log
58 | local_settings.py
59 | db.sqlite3
60 | db.sqlite3-journal
61 |
62 | # Flask stuff:
63 | instance/
64 | .webassets-cache
65 |
66 | # Scrapy stuff:
67 | .scrapy
68 |
69 | # Sphinx documentation
70 | docs/_build/
71 |
72 | # PyBuilder
73 | .pybuilder/
74 | target/
75 |
76 | # Jupyter Notebook
77 | .ipynb_checkpoints
78 |
79 | # IPython
80 | profile_default/
81 | ipython_config.py
82 |
83 | # pyenv
84 | # For a library or package, you might want to ignore these files since the code is
85 | # intended to run in multiple environments; otherwise, check them in:
86 | # .python-version
87 |
88 | # pipenv
89 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
90 | # However, in case of collaboration, if having platform-specific dependencies or dependencies
91 | # having no cross-platform support, pipenv may install dependencies that don't work, or not
92 | # install all needed dependencies.
93 | #Pipfile.lock
94 |
95 | # poetry
96 | # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
97 | # This is especially recommended for binary packages to ensure reproducibility, and is more
98 | # commonly ignored for libraries.
99 | # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
100 | #poetry.lock
101 |
102 | # pdm
103 | # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
104 | #pdm.lock
105 | # pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
106 | # in version control.
107 | # https://pdm.fming.dev/#use-with-ide
108 | .pdm.toml
109 |
110 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
111 | __pypackages__/
112 |
113 | # Celery stuff
114 | celerybeat-schedule
115 | celerybeat.pid
116 |
117 | # SageMath parsed files
118 | *.sage.py
119 |
120 | # Environments
121 | .env
122 | .venv
123 | env/
124 | venv/
125 | ENV/
126 | env.bak/
127 | venv.bak/
128 |
129 | # Spyder project settings
130 | .spyderproject
131 | .spyproject
132 |
133 | # Rope project settings
134 | .ropeproject
135 |
136 | # mkdocs documentation
137 | /site
138 |
139 | # mypy
140 | .mypy_cache/
141 | .dmypy.json
142 | dmypy.json
143 |
144 | # Pyre type checker
145 | .pyre/
146 |
147 | # pytype static type analyzer
148 | .pytype/
149 |
150 | # Cython debug symbols
151 | cython_debug/
152 |
153 | # PyCharm
154 | # JetBrains specific template is maintained in a separate JetBrains.gitignore that can
155 | # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
156 | # and can be added to the global gitignore or merged into this file. For a more nuclear
157 | # option (not recommended) you can uncomment the following to ignore the entire idea folder.
158 | .idea/
159 |
160 | cache/
161 | log/
162 | proxy/
--------------------------------------------------------------------------------
/instock/core/backtest/.gitignore:
--------------------------------------------------------------------------------
1 | # Byte-compiled / optimized / DLL files
2 | __pycache__/
3 | *.py[cod]
4 | *$py.class
5 |
6 | # C extensions
7 | *.so
8 |
9 | # Distribution / packaging
10 | .Python
11 | build/
12 | develop-eggs/
13 | dist/
14 | downloads/
15 | eggs/
16 | .eggs/
17 | lib/
18 | lib64/
19 | parts/
20 | sdist/
21 | var/
22 | wheels/
23 | share/python-wheels/
24 | *.egg-info/
25 | .installed.cfg
26 | *.egg
27 | MANIFEST
28 |
29 | # PyInstaller
30 | # Usually these files are written by a python script from a template
31 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
32 | *.manifest
33 | *.spec
34 |
35 | # Installer logs
36 | pip-log.txt
37 | pip-delete-this-directory.txt
38 |
39 | # Unit test / coverage reports
40 | htmlcov/
41 | .tox/
42 | .nox/
43 | .coverage
44 | .coverage.*
45 | .cache
46 | nosetests.xml
47 | coverage.xml
48 | *.cover
49 | *.py,cover
50 | .hypothesis/
51 | .pytest_cache/
52 | cover/
53 |
54 | # Translations
55 | *.mo
56 | *.pot
57 |
58 | # Django stuff:
59 | *.log
60 | local_settings.py
61 | db.sqlite3
62 | db.sqlite3-journal
63 |
64 | # Flask stuff:
65 | instance/
66 | .webassets-cache
67 |
68 | # Scrapy stuff:
69 | .scrapy
70 |
71 | # Sphinx documentation
72 | docs/_build/
73 |
74 | # PyBuilder
75 | .pybuilder/
76 | target/
77 |
78 | # Jupyter Notebook
79 | .ipynb_checkpoints
80 |
81 | # IPython
82 | profile_default/
83 | ipython_config.py
84 |
85 | # pyenv
86 | # For a library or package, you might want to ignore these files since the code is
87 | # intended to run in multiple environments; otherwise, check them in:
88 | # .python-version
89 |
90 | # pipenv
91 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
92 | # However, in case of collaboration, if having platform-specific dependencies or dependencies
93 | # having no cross-platform support, pipenv may install dependencies that don't work, or not
94 | # install all needed dependencies.
95 | #Pipfile.lock
96 |
97 | # poetry
98 | # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
99 | # This is especially recommended for binary packages to ensure reproducibility, and is more
100 | # commonly ignored for libraries.
101 | # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
102 | #poetry.lock
103 |
104 | # pdm
105 | # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
106 | #pdm.lock
107 | # pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
108 | # in version control.
109 | # https://pdm.fming.dev/#use-with-ide
110 | .pdm.toml
111 |
112 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
113 | __pypackages__/
114 |
115 | # Celery stuff
116 | celerybeat-schedule
117 | celerybeat.pid
118 |
119 | # SageMath parsed files
120 | *.sage.py
121 |
122 | # Environments
123 | .env
124 | .venv
125 | env/
126 | venv/
127 | ENV/
128 | env.bak/
129 | venv.bak/
130 |
131 | # Spyder project settings
132 | .spyderproject
133 | .spyproject
134 |
135 | # Rope project settings
136 | .ropeproject
137 |
138 | # mkdocs documentation
139 | /site
140 |
141 | # mypy
142 | .mypy_cache/
143 | .dmypy.json
144 | dmypy.json
145 |
146 | # Pyre type checker
147 | .pyre/
148 |
149 | # pytype static type analyzer
150 | .pytype/
151 |
152 | # Cython debug symbols
153 | cython_debug/
154 |
155 | # PyCharm
156 | # JetBrains specific template is maintained in a separate JetBrains.gitignore that can
157 | # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
158 | # and can be added to the global gitignore or merged into this file. For a more nuclear
159 | # option (not recommended) you can uncomment the following to ignore the entire idea folder.
160 | .idea/
161 |
--------------------------------------------------------------------------------
/instock/core/indicator/.gitignore:
--------------------------------------------------------------------------------
1 | # Byte-compiled / optimized / DLL files
2 | __pycache__/
3 | *.py[cod]
4 | *$py.class
5 |
6 | # C extensions
7 | *.so
8 |
9 | # Distribution / packaging
10 | .Python
11 | build/
12 | develop-eggs/
13 | dist/
14 | downloads/
15 | eggs/
16 | .eggs/
17 | lib/
18 | lib64/
19 | parts/
20 | sdist/
21 | var/
22 | wheels/
23 | share/python-wheels/
24 | *.egg-info/
25 | .installed.cfg
26 | *.egg
27 | MANIFEST
28 |
29 | # PyInstaller
30 | # Usually these files are written by a python script from a template
31 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
32 | *.manifest
33 | *.spec
34 |
35 | # Installer logs
36 | pip-log.txt
37 | pip-delete-this-directory.txt
38 |
39 | # Unit test / coverage reports
40 | htmlcov/
41 | .tox/
42 | .nox/
43 | .coverage
44 | .coverage.*
45 | .cache
46 | nosetests.xml
47 | coverage.xml
48 | *.cover
49 | *.py,cover
50 | .hypothesis/
51 | .pytest_cache/
52 | cover/
53 |
54 | # Translations
55 | *.mo
56 | *.pot
57 |
58 | # Django stuff:
59 | *.log
60 | local_settings.py
61 | db.sqlite3
62 | db.sqlite3-journal
63 |
64 | # Flask stuff:
65 | instance/
66 | .webassets-cache
67 |
68 | # Scrapy stuff:
69 | .scrapy
70 |
71 | # Sphinx documentation
72 | docs/_build/
73 |
74 | # PyBuilder
75 | .pybuilder/
76 | target/
77 |
78 | # Jupyter Notebook
79 | .ipynb_checkpoints
80 |
81 | # IPython
82 | profile_default/
83 | ipython_config.py
84 |
85 | # pyenv
86 | # For a library or package, you might want to ignore these files since the code is
87 | # intended to run in multiple environments; otherwise, check them in:
88 | # .python-version
89 |
90 | # pipenv
91 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
92 | # However, in case of collaboration, if having platform-specific dependencies or dependencies
93 | # having no cross-platform support, pipenv may install dependencies that don't work, or not
94 | # install all needed dependencies.
95 | #Pipfile.lock
96 |
97 | # poetry
98 | # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
99 | # This is especially recommended for binary packages to ensure reproducibility, and is more
100 | # commonly ignored for libraries.
101 | # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
102 | #poetry.lock
103 |
104 | # pdm
105 | # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
106 | #pdm.lock
107 | # pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
108 | # in version control.
109 | # https://pdm.fming.dev/#use-with-ide
110 | .pdm.toml
111 |
112 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
113 | __pypackages__/
114 |
115 | # Celery stuff
116 | celerybeat-schedule
117 | celerybeat.pid
118 |
119 | # SageMath parsed files
120 | *.sage.py
121 |
122 | # Environments
123 | .env
124 | .venv
125 | env/
126 | venv/
127 | ENV/
128 | env.bak/
129 | venv.bak/
130 |
131 | # Spyder project settings
132 | .spyderproject
133 | .spyproject
134 |
135 | # Rope project settings
136 | .ropeproject
137 |
138 | # mkdocs documentation
139 | /site
140 |
141 | # mypy
142 | .mypy_cache/
143 | .dmypy.json
144 | dmypy.json
145 |
146 | # Pyre type checker
147 | .pyre/
148 |
149 | # pytype static type analyzer
150 | .pytype/
151 |
152 | # Cython debug symbols
153 | cython_debug/
154 |
155 | # PyCharm
156 | # JetBrains specific template is maintained in a separate JetBrains.gitignore that can
157 | # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
158 | # and can be added to the global gitignore or merged into this file. For a more nuclear
159 | # option (not recommended) you can uncomment the following to ignore the entire idea folder.
160 | .idea/
161 |
--------------------------------------------------------------------------------
/instock/core/pattern/.gitignore:
--------------------------------------------------------------------------------
1 | # Byte-compiled / optimized / DLL files
2 | __pycache__/
3 | *.py[cod]
4 | *$py.class
5 |
6 | # C extensions
7 | *.so
8 |
9 | # Distribution / packaging
10 | .Python
11 | build/
12 | develop-eggs/
13 | dist/
14 | downloads/
15 | eggs/
16 | .eggs/
17 | lib/
18 | lib64/
19 | parts/
20 | sdist/
21 | var/
22 | wheels/
23 | share/python-wheels/
24 | *.egg-info/
25 | .installed.cfg
26 | *.egg
27 | MANIFEST
28 |
29 | # PyInstaller
30 | # Usually these files are written by a python script from a template
31 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
32 | *.manifest
33 | *.spec
34 |
35 | # Installer logs
36 | pip-log.txt
37 | pip-delete-this-directory.txt
38 |
39 | # Unit test / coverage reports
40 | htmlcov/
41 | .tox/
42 | .nox/
43 | .coverage
44 | .coverage.*
45 | .cache
46 | nosetests.xml
47 | coverage.xml
48 | *.cover
49 | *.py,cover
50 | .hypothesis/
51 | .pytest_cache/
52 | cover/
53 |
54 | # Translations
55 | *.mo
56 | *.pot
57 |
58 | # Django stuff:
59 | *.log
60 | local_settings.py
61 | db.sqlite3
62 | db.sqlite3-journal
63 |
64 | # Flask stuff:
65 | instance/
66 | .webassets-cache
67 |
68 | # Scrapy stuff:
69 | .scrapy
70 |
71 | # Sphinx documentation
72 | docs/_build/
73 |
74 | # PyBuilder
75 | .pybuilder/
76 | target/
77 |
78 | # Jupyter Notebook
79 | .ipynb_checkpoints
80 |
81 | # IPython
82 | profile_default/
83 | ipython_config.py
84 |
85 | # pyenv
86 | # For a library or package, you might want to ignore these files since the code is
87 | # intended to run in multiple environments; otherwise, check them in:
88 | # .python-version
89 |
90 | # pipenv
91 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
92 | # However, in case of collaboration, if having platform-specific dependencies or dependencies
93 | # having no cross-platform support, pipenv may install dependencies that don't work, or not
94 | # install all needed dependencies.
95 | #Pipfile.lock
96 |
97 | # poetry
98 | # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
99 | # This is especially recommended for binary packages to ensure reproducibility, and is more
100 | # commonly ignored for libraries.
101 | # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
102 | #poetry.lock
103 |
104 | # pdm
105 | # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
106 | #pdm.lock
107 | # pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
108 | # in version control.
109 | # https://pdm.fming.dev/#use-with-ide
110 | .pdm.toml
111 |
112 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
113 | __pypackages__/
114 |
115 | # Celery stuff
116 | celerybeat-schedule
117 | celerybeat.pid
118 |
119 | # SageMath parsed files
120 | *.sage.py
121 |
122 | # Environments
123 | .env
124 | .venv
125 | env/
126 | venv/
127 | ENV/
128 | env.bak/
129 | venv.bak/
130 |
131 | # Spyder project settings
132 | .spyderproject
133 | .spyproject
134 |
135 | # Rope project settings
136 | .ropeproject
137 |
138 | # mkdocs documentation
139 | /site
140 |
141 | # mypy
142 | .mypy_cache/
143 | .dmypy.json
144 | dmypy.json
145 |
146 | # Pyre type checker
147 | .pyre/
148 |
149 | # pytype static type analyzer
150 | .pytype/
151 |
152 | # Cython debug symbols
153 | cython_debug/
154 |
155 | # PyCharm
156 | # JetBrains specific template is maintained in a separate JetBrains.gitignore that can
157 | # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
158 | # and can be added to the global gitignore or merged into this file. For a more nuclear
159 | # option (not recommended) you can uncomment the following to ignore the entire idea folder.
160 | .idea/
161 |
--------------------------------------------------------------------------------
/instock/core/strategy/.gitignore:
--------------------------------------------------------------------------------
1 | # Byte-compiled / optimized / DLL files
2 | __pycache__/
3 | *.py[cod]
4 | *$py.class
5 |
6 | # C extensions
7 | *.so
8 |
9 | # Distribution / packaging
10 | .Python
11 | build/
12 | develop-eggs/
13 | dist/
14 | downloads/
15 | eggs/
16 | .eggs/
17 | lib/
18 | lib64/
19 | parts/
20 | sdist/
21 | var/
22 | wheels/
23 | share/python-wheels/
24 | *.egg-info/
25 | .installed.cfg
26 | *.egg
27 | MANIFEST
28 |
29 | # PyInstaller
30 | # Usually these files are written by a python script from a template
31 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
32 | *.manifest
33 | *.spec
34 |
35 | # Installer logs
36 | pip-log.txt
37 | pip-delete-this-directory.txt
38 |
39 | # Unit test / coverage reports
40 | htmlcov/
41 | .tox/
42 | .nox/
43 | .coverage
44 | .coverage.*
45 | .cache
46 | nosetests.xml
47 | coverage.xml
48 | *.cover
49 | *.py,cover
50 | .hypothesis/
51 | .pytest_cache/
52 | cover/
53 |
54 | # Translations
55 | *.mo
56 | *.pot
57 |
58 | # Django stuff:
59 | *.log
60 | local_settings.py
61 | db.sqlite3
62 | db.sqlite3-journal
63 |
64 | # Flask stuff:
65 | instance/
66 | .webassets-cache
67 |
68 | # Scrapy stuff:
69 | .scrapy
70 |
71 | # Sphinx documentation
72 | docs/_build/
73 |
74 | # PyBuilder
75 | .pybuilder/
76 | target/
77 |
78 | # Jupyter Notebook
79 | .ipynb_checkpoints
80 |
81 | # IPython
82 | profile_default/
83 | ipython_config.py
84 |
85 | # pyenv
86 | # For a library or package, you might want to ignore these files since the code is
87 | # intended to run in multiple environments; otherwise, check them in:
88 | # .python-version
89 |
90 | # pipenv
91 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
92 | # However, in case of collaboration, if having platform-specific dependencies or dependencies
93 | # having no cross-platform support, pipenv may install dependencies that don't work, or not
94 | # install all needed dependencies.
95 | #Pipfile.lock
96 |
97 | # poetry
98 | # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
99 | # This is especially recommended for binary packages to ensure reproducibility, and is more
100 | # commonly ignored for libraries.
101 | # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
102 | #poetry.lock
103 |
104 | # pdm
105 | # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
106 | #pdm.lock
107 | # pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
108 | # in version control.
109 | # https://pdm.fming.dev/#use-with-ide
110 | .pdm.toml
111 |
112 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
113 | __pypackages__/
114 |
115 | # Celery stuff
116 | celerybeat-schedule
117 | celerybeat.pid
118 |
119 | # SageMath parsed files
120 | *.sage.py
121 |
122 | # Environments
123 | .env
124 | .venv
125 | env/
126 | venv/
127 | ENV/
128 | env.bak/
129 | venv.bak/
130 |
131 | # Spyder project settings
132 | .spyderproject
133 | .spyproject
134 |
135 | # Rope project settings
136 | .ropeproject
137 |
138 | # mkdocs documentation
139 | /site
140 |
141 | # mypy
142 | .mypy_cache/
143 | .dmypy.json
144 | dmypy.json
145 |
146 | # Pyre type checker
147 | .pyre/
148 |
149 | # pytype static type analyzer
150 | .pytype/
151 |
152 | # Cython debug symbols
153 | cython_debug/
154 |
155 | # PyCharm
156 | # JetBrains specific template is maintained in a separate JetBrains.gitignore that can
157 | # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
158 | # and can be added to the global gitignore or merged into this file. For a more nuclear
159 | # option (not recommended) you can uncomment the following to ignore the entire idea folder.
160 | .idea/
161 |
--------------------------------------------------------------------------------
/instock/trade/robot/.gitignore:
--------------------------------------------------------------------------------
1 | # Byte-compiled / optimized / DLL files
2 | __pycache__/
3 | *.py[cod]
4 | *$py.class
5 |
6 | # C extensions
7 | *.so
8 |
9 | # Distribution / packaging
10 | .Python
11 | build/
12 | develop-eggs/
13 | dist/
14 | downloads/
15 | eggs/
16 | .eggs/
17 | lib/
18 | lib64/
19 | parts/
20 | sdist/
21 | var/
22 | wheels/
23 | share/python-wheels/
24 | *.egg-info/
25 | .installed.cfg
26 | *.egg
27 | MANIFEST
28 |
29 | # PyInstaller
30 | # Usually these files are written by a python script from a template
31 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
32 | *.manifest
33 | *.spec
34 |
35 | # Installer logs
36 | pip-log.txt
37 | pip-delete-this-directory.txt
38 |
39 | # Unit test / coverage reports
40 | htmlcov/
41 | .tox/
42 | .nox/
43 | .coverage
44 | .coverage.*
45 | .cache
46 | nosetests.xml
47 | coverage.xml
48 | *.cover
49 | *.py,cover
50 | .hypothesis/
51 | .pytest_cache/
52 | cover/
53 |
54 | # Translations
55 | *.mo
56 | *.pot
57 |
58 | # Django stuff:
59 | *.log
60 | local_settings.py
61 | db.sqlite3
62 | db.sqlite3-journal
63 |
64 | # Flask stuff:
65 | instance/
66 | .webassets-cache
67 |
68 | # Scrapy stuff:
69 | .scrapy
70 |
71 | # Sphinx documentation
72 | docs/_build/
73 |
74 | # PyBuilder
75 | .pybuilder/
76 | target/
77 |
78 | # Jupyter Notebook
79 | .ipynb_checkpoints
80 |
81 | # IPython
82 | profile_default/
83 | ipython_config.py
84 |
85 | # pyenv
86 | # For a library or package, you might want to ignore these files since the code is
87 | # intended to run in multiple environments; otherwise, check them in:
88 | # .python-version
89 |
90 | # pipenv
91 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
92 | # However, in case of collaboration, if having platform-specific dependencies or dependencies
93 | # having no cross-platform support, pipenv may install dependencies that don't work, or not
94 | # install all needed dependencies.
95 | #Pipfile.lock
96 |
97 | # poetry
98 | # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
99 | # This is especially recommended for binary packages to ensure reproducibility, and is more
100 | # commonly ignored for libraries.
101 | # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
102 | #poetry.lock
103 |
104 | # pdm
105 | # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
106 | #pdm.lock
107 | # pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
108 | # in version control.
109 | # https://pdm.fming.dev/#use-with-ide
110 | .pdm.toml
111 |
112 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
113 | __pypackages__/
114 |
115 | # Celery stuff
116 | celerybeat-schedule
117 | celerybeat.pid
118 |
119 | # SageMath parsed files
120 | *.sage.py
121 |
122 | # Environments
123 | .env
124 | .venv
125 | env/
126 | venv/
127 | ENV/
128 | env.bak/
129 | venv.bak/
130 |
131 | # Spyder project settings
132 | .spyderproject
133 | .spyproject
134 |
135 | # Rope project settings
136 | .ropeproject
137 |
138 | # mkdocs documentation
139 | /site
140 |
141 | # mypy
142 | .mypy_cache/
143 | .dmypy.json
144 | dmypy.json
145 |
146 | # Pyre type checker
147 | .pyre/
148 |
149 | # pytype static type analyzer
150 | .pytype/
151 |
152 | # Cython debug symbols
153 | cython_debug/
154 |
155 | # PyCharm
156 | # JetBrains specific template is maintained in a separate JetBrains.gitignore that can
157 | # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
158 | # and can be added to the global gitignore or merged into this file. For a more nuclear
159 | # option (not recommended) you can uncomment the following to ignore the entire idea folder.
160 | .idea/
161 |
--------------------------------------------------------------------------------
/instock/trade/robot/engine/.gitignore:
--------------------------------------------------------------------------------
1 | # Byte-compiled / optimized / DLL files
2 | __pycache__/
3 | *.py[cod]
4 | *$py.class
5 |
6 | # C extensions
7 | *.so
8 |
9 | # Distribution / packaging
10 | .Python
11 | build/
12 | develop-eggs/
13 | dist/
14 | downloads/
15 | eggs/
16 | .eggs/
17 | lib/
18 | lib64/
19 | parts/
20 | sdist/
21 | var/
22 | wheels/
23 | share/python-wheels/
24 | *.egg-info/
25 | .installed.cfg
26 | *.egg
27 | MANIFEST
28 |
29 | # PyInstaller
30 | # Usually these files are written by a python script from a template
31 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
32 | *.manifest
33 | *.spec
34 |
35 | # Installer logs
36 | pip-log.txt
37 | pip-delete-this-directory.txt
38 |
39 | # Unit test / coverage reports
40 | htmlcov/
41 | .tox/
42 | .nox/
43 | .coverage
44 | .coverage.*
45 | .cache
46 | nosetests.xml
47 | coverage.xml
48 | *.cover
49 | *.py,cover
50 | .hypothesis/
51 | .pytest_cache/
52 | cover/
53 |
54 | # Translations
55 | *.mo
56 | *.pot
57 |
58 | # Django stuff:
59 | *.log
60 | local_settings.py
61 | db.sqlite3
62 | db.sqlite3-journal
63 |
64 | # Flask stuff:
65 | instance/
66 | .webassets-cache
67 |
68 | # Scrapy stuff:
69 | .scrapy
70 |
71 | # Sphinx documentation
72 | docs/_build/
73 |
74 | # PyBuilder
75 | .pybuilder/
76 | target/
77 |
78 | # Jupyter Notebook
79 | .ipynb_checkpoints
80 |
81 | # IPython
82 | profile_default/
83 | ipython_config.py
84 |
85 | # pyenv
86 | # For a library or package, you might want to ignore these files since the code is
87 | # intended to run in multiple environments; otherwise, check them in:
88 | # .python-version
89 |
90 | # pipenv
91 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
92 | # However, in case of collaboration, if having platform-specific dependencies or dependencies
93 | # having no cross-platform support, pipenv may install dependencies that don't work, or not
94 | # install all needed dependencies.
95 | #Pipfile.lock
96 |
97 | # poetry
98 | # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
99 | # This is especially recommended for binary packages to ensure reproducibility, and is more
100 | # commonly ignored for libraries.
101 | # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
102 | #poetry.lock
103 |
104 | # pdm
105 | # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
106 | #pdm.lock
107 | # pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
108 | # in version control.
109 | # https://pdm.fming.dev/#use-with-ide
110 | .pdm.toml
111 |
112 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
113 | __pypackages__/
114 |
115 | # Celery stuff
116 | celerybeat-schedule
117 | celerybeat.pid
118 |
119 | # SageMath parsed files
120 | *.sage.py
121 |
122 | # Environments
123 | .env
124 | .venv
125 | env/
126 | venv/
127 | ENV/
128 | env.bak/
129 | venv.bak/
130 |
131 | # Spyder project settings
132 | .spyderproject
133 | .spyproject
134 |
135 | # Rope project settings
136 | .ropeproject
137 |
138 | # mkdocs documentation
139 | /site
140 |
141 | # mypy
142 | .mypy_cache/
143 | .dmypy.json
144 | dmypy.json
145 |
146 | # Pyre type checker
147 | .pyre/
148 |
149 | # pytype static type analyzer
150 | .pytype/
151 |
152 | # Cython debug symbols
153 | cython_debug/
154 |
155 | # PyCharm
156 | # JetBrains specific template is maintained in a separate JetBrains.gitignore that can
157 | # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
158 | # and can be added to the global gitignore or merged into this file. For a more nuclear
159 | # option (not recommended) you can uncomment the following to ignore the entire idea folder.
160 | .idea/
161 |
--------------------------------------------------------------------------------
/instock/trade/strategies/.gitignore:
--------------------------------------------------------------------------------
1 | # Byte-compiled / optimized / DLL files
2 | __pycache__/
3 | *.py[cod]
4 | *$py.class
5 |
6 | # C extensions
7 | *.so
8 |
9 | # Distribution / packaging
10 | .Python
11 | build/
12 | develop-eggs/
13 | dist/
14 | downloads/
15 | eggs/
16 | .eggs/
17 | lib/
18 | lib64/
19 | parts/
20 | sdist/
21 | var/
22 | wheels/
23 | share/python-wheels/
24 | *.egg-info/
25 | .installed.cfg
26 | *.egg
27 | MANIFEST
28 |
29 | # PyInstaller
30 | # Usually these files are written by a python script from a template
31 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
32 | *.manifest
33 | *.spec
34 |
35 | # Installer logs
36 | pip-log.txt
37 | pip-delete-this-directory.txt
38 |
39 | # Unit test / coverage reports
40 | htmlcov/
41 | .tox/
42 | .nox/
43 | .coverage
44 | .coverage.*
45 | .cache
46 | nosetests.xml
47 | coverage.xml
48 | *.cover
49 | *.py,cover
50 | .hypothesis/
51 | .pytest_cache/
52 | cover/
53 |
54 | # Translations
55 | *.mo
56 | *.pot
57 |
58 | # Django stuff:
59 | *.log
60 | local_settings.py
61 | db.sqlite3
62 | db.sqlite3-journal
63 |
64 | # Flask stuff:
65 | instance/
66 | .webassets-cache
67 |
68 | # Scrapy stuff:
69 | .scrapy
70 |
71 | # Sphinx documentation
72 | docs/_build/
73 |
74 | # PyBuilder
75 | .pybuilder/
76 | target/
77 |
78 | # Jupyter Notebook
79 | .ipynb_checkpoints
80 |
81 | # IPython
82 | profile_default/
83 | ipython_config.py
84 |
85 | # pyenv
86 | # For a library or package, you might want to ignore these files since the code is
87 | # intended to run in multiple environments; otherwise, check them in:
88 | # .python-version
89 |
90 | # pipenv
91 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
92 | # However, in case of collaboration, if having platform-specific dependencies or dependencies
93 | # having no cross-platform support, pipenv may install dependencies that don't work, or not
94 | # install all needed dependencies.
95 | #Pipfile.lock
96 |
97 | # poetry
98 | # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
99 | # This is especially recommended for binary packages to ensure reproducibility, and is more
100 | # commonly ignored for libraries.
101 | # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
102 | #poetry.lock
103 |
104 | # pdm
105 | # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
106 | #pdm.lock
107 | # pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
108 | # in version control.
109 | # https://pdm.fming.dev/#use-with-ide
110 | .pdm.toml
111 |
112 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
113 | __pypackages__/
114 |
115 | # Celery stuff
116 | celerybeat-schedule
117 | celerybeat.pid
118 |
119 | # SageMath parsed files
120 | *.sage.py
121 |
122 | # Environments
123 | .env
124 | .venv
125 | env/
126 | venv/
127 | ENV/
128 | env.bak/
129 | venv.bak/
130 |
131 | # Spyder project settings
132 | .spyderproject
133 | .spyproject
134 |
135 | # Rope project settings
136 | .ropeproject
137 |
138 | # mkdocs documentation
139 | /site
140 |
141 | # mypy
142 | .mypy_cache/
143 | .dmypy.json
144 | dmypy.json
145 |
146 | # Pyre type checker
147 | .pyre/
148 |
149 | # pytype static type analyzer
150 | .pytype/
151 |
152 | # Cython debug symbols
153 | cython_debug/
154 |
155 | # PyCharm
156 | # JetBrains specific template is maintained in a separate JetBrains.gitignore that can
157 | # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
158 | # and can be added to the global gitignore or merged into this file. For a more nuclear
159 | # option (not recommended) you can uncomment the following to ignore the entire idea folder.
160 | .idea/
161 |
--------------------------------------------------------------------------------
/instock/trade/robot/infrastructure/.gitignore:
--------------------------------------------------------------------------------
1 | # Byte-compiled / optimized / DLL files
2 | __pycache__/
3 | *.py[cod]
4 | *$py.class
5 |
6 | # C extensions
7 | *.so
8 |
9 | # Distribution / packaging
10 | .Python
11 | build/
12 | develop-eggs/
13 | dist/
14 | downloads/
15 | eggs/
16 | .eggs/
17 | lib/
18 | lib64/
19 | parts/
20 | sdist/
21 | var/
22 | wheels/
23 | share/python-wheels/
24 | *.egg-info/
25 | .installed.cfg
26 | *.egg
27 | MANIFEST
28 |
29 | # PyInstaller
30 | # Usually these files are written by a python script from a template
31 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
32 | *.manifest
33 | *.spec
34 |
35 | # Installer logs
36 | pip-log.txt
37 | pip-delete-this-directory.txt
38 |
39 | # Unit test / coverage reports
40 | htmlcov/
41 | .tox/
42 | .nox/
43 | .coverage
44 | .coverage.*
45 | .cache
46 | nosetests.xml
47 | coverage.xml
48 | *.cover
49 | *.py,cover
50 | .hypothesis/
51 | .pytest_cache/
52 | cover/
53 |
54 | # Translations
55 | *.mo
56 | *.pot
57 |
58 | # Django stuff:
59 | *.log
60 | local_settings.py
61 | db.sqlite3
62 | db.sqlite3-journal
63 |
64 | # Flask stuff:
65 | instance/
66 | .webassets-cache
67 |
68 | # Scrapy stuff:
69 | .scrapy
70 |
71 | # Sphinx documentation
72 | docs/_build/
73 |
74 | # PyBuilder
75 | .pybuilder/
76 | target/
77 |
78 | # Jupyter Notebook
79 | .ipynb_checkpoints
80 |
81 | # IPython
82 | profile_default/
83 | ipython_config.py
84 |
85 | # pyenv
86 | # For a library or package, you might want to ignore these files since the code is
87 | # intended to run in multiple environments; otherwise, check them in:
88 | # .python-version
89 |
90 | # pipenv
91 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
92 | # However, in case of collaboration, if having platform-specific dependencies or dependencies
93 | # having no cross-platform support, pipenv may install dependencies that don't work, or not
94 | # install all needed dependencies.
95 | #Pipfile.lock
96 |
97 | # poetry
98 | # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
99 | # This is especially recommended for binary packages to ensure reproducibility, and is more
100 | # commonly ignored for libraries.
101 | # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
102 | #poetry.lock
103 |
104 | # pdm
105 | # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
106 | #pdm.lock
107 | # pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
108 | # in version control.
109 | # https://pdm.fming.dev/#use-with-ide
110 | .pdm.toml
111 |
112 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
113 | __pypackages__/
114 |
115 | # Celery stuff
116 | celerybeat-schedule
117 | celerybeat.pid
118 |
119 | # SageMath parsed files
120 | *.sage.py
121 |
122 | # Environments
123 | .env
124 | .venv
125 | env/
126 | venv/
127 | ENV/
128 | env.bak/
129 | venv.bak/
130 |
131 | # Spyder project settings
132 | .spyderproject
133 | .spyproject
134 |
135 | # Rope project settings
136 | .ropeproject
137 |
138 | # mkdocs documentation
139 | /site
140 |
141 | # mypy
142 | .mypy_cache/
143 | .dmypy.json
144 | dmypy.json
145 |
146 | # Pyre type checker
147 | .pyre/
148 |
149 | # pytype static type analyzer
150 | .pytype/
151 |
152 | # Cython debug symbols
153 | cython_debug/
154 |
155 | # PyCharm
156 | # JetBrains specific template is maintained in a separate JetBrains.gitignore that can
157 | # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
158 | # and can be added to the global gitignore or merged into this file. For a more nuclear
159 | # option (not recommended) you can uncomment the following to ignore the entire idea folder.
160 | .idea/
161 |
--------------------------------------------------------------------------------
/instock/web/templates/common/left_menu.html:
--------------------------------------------------------------------------------
1 | {% block left_menu %}
2 |
3 |
4 |
5 |
6 |
7 |
26 |
36 |
39 |
93 | {% end %}
--------------------------------------------------------------------------------
/instock/core/crawling/stock_fhps_em.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding:utf-8 -*-
3 | """
4 | Date: 2023/4/7 15:22
5 | Desc: 东方财富网-数据中心-年报季报-分红送配
6 | https://data.eastmoney.com/yjfp/
7 | """
8 | import pandas as pd
9 | import requests
10 | from tqdm import tqdm
11 |
12 | __author__ = 'myh '
13 | __date__ = '2023/6/27 '
14 |
15 |
16 | def stock_fhps_em(date: str = "20231231") -> pd.DataFrame:
17 | """
18 | 东方财富网-数据中心-年报季报-分红送配
19 | https://data.eastmoney.com/yjfp/
20 | :param date: 分红送配报告期
21 | :type date: str
22 | :return: 分红送配
23 | :rtype: pandas.DataFrame
24 | """
25 | import warnings
26 |
27 | warnings.simplefilter(action="ignore", category=FutureWarning)
28 |
29 | url = "https://datacenter-web.eastmoney.com/api/data/v1/get"
30 | params = {
31 | "sortColumns": "PLAN_NOTICE_DATE",
32 | "sortTypes": "-1",
33 | "pageSize": "500",
34 | "pageNumber": "1",
35 | "reportName": "RPT_SHAREBONUS_DET",
36 | "columns": "ALL",
37 | "quoteColumns": "",
38 | "js": '{"data":(x),"pages":(tp)}',
39 | "source": "WEB",
40 | "client": "WEB",
41 | "filter": f"""(REPORT_DATE='{"-".join([date[:4], date[4:6], date[6:]])}')""",
42 | }
43 |
44 | r = requests.get(url, params=params)
45 | data_json = r.json()
46 | total_pages = int(data_json["result"]["pages"])
47 | big_df = pd.DataFrame()
48 | for page in tqdm(range(1, total_pages + 1), leave=False):
49 | params.update({"pageNumber": page})
50 | r = requests.get(url, params=params)
51 | data_json = r.json()
52 | temp_df = pd.DataFrame(data_json["result"]["data"])
53 | if not temp_df.empty:
54 | big_df = pd.concat(objs=[big_df, temp_df], ignore_index=True)
55 |
56 | big_df.columns = [
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 | ]
88 | big_df = big_df[
89 | [
90 | "代码",
91 | "名称",
92 | "送转股份-送转总比例",
93 | "送转股份-送转比例",
94 | "送转股份-转股比例",
95 | "现金分红-现金分红比例",
96 | "现金分红-股息率",
97 | "每股收益",
98 | "每股净资产",
99 | "每股公积金",
100 | "每股未分配利润",
101 | "净利润同比增长",
102 | "总股本",
103 | "预案公告日",
104 | "股权登记日",
105 | "除权除息日",
106 | "方案进度",
107 | "最新公告日期",
108 | ]
109 | ]
110 | big_df["送转股份-送转总比例"] = pd.to_numeric(
111 | big_df["送转股份-送转总比例"], errors="coerce"
112 | )
113 | big_df["送转股份-送转比例"] = pd.to_numeric(
114 | big_df["送转股份-送转比例"], errors="coerce"
115 | )
116 | big_df["送转股份-转股比例"] = pd.to_numeric(
117 | big_df["送转股份-转股比例"], errors="coerce"
118 | )
119 | big_df["现金分红-现金分红比例"] = pd.to_numeric(
120 | big_df["现金分红-现金分红比例"], errors="coerce"
121 | )
122 | big_df["现金分红-股息率"] = pd.to_numeric(
123 | big_df["现金分红-股息率"], errors="coerce"
124 | )
125 | big_df["每股收益"] = pd.to_numeric(big_df["每股收益"], errors="coerce")
126 | big_df["每股净资产"] = pd.to_numeric(big_df["每股净资产"], errors="coerce")
127 | big_df["每股公积金"] = pd.to_numeric(big_df["每股公积金"], errors="coerce")
128 | big_df["每股未分配利润"] = pd.to_numeric(big_df["每股未分配利润"], errors="coerce")
129 | big_df["净利润同比增长"] = pd.to_numeric(big_df["净利润同比增长"], errors="coerce")
130 | big_df["总股本"] = pd.to_numeric(big_df["总股本"], errors="coerce")
131 |
132 | big_df["预案公告日"] = pd.to_datetime(big_df["预案公告日"], errors="coerce").dt.date
133 | big_df["股权登记日"] = pd.to_datetime(big_df["股权登记日"], errors="coerce").dt.date
134 | big_df["除权除息日"] = pd.to_datetime(big_df["除权除息日"], errors="coerce").dt.date
135 | big_df["最新公告日期"] = pd.to_datetime(
136 | big_df["最新公告日期"], errors="coerce"
137 | ).dt.date
138 | big_df.sort_values(["最新公告日期"], inplace=True, ignore_index=True)
139 | return big_df
140 |
141 |
142 | if __name__ == "__main__":
143 | stock_fhps_em_df = stock_fhps_em(date="20221231")
144 | print(stock_fhps_em_df)
145 |
--------------------------------------------------------------------------------
/instock/lib/trade_time.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | # -*- coding: utf-8 -*-
3 |
4 | import datetime
5 | from instock.core.singleton_trade_date import stock_trade_date
6 |
7 | __author__ = 'myh '
8 | __date__ = '2023/4/10 '
9 |
10 |
11 | def is_trade_date(date=None):
12 | trade_date = stock_trade_date().get_data()
13 | if trade_date is None:
14 | return False
15 | if date in trade_date:
16 | return True
17 | else:
18 | return False
19 |
20 |
21 | def get_previous_trade_date(date):
22 | trade_date = stock_trade_date().get_data()
23 | if trade_date is None:
24 | return date
25 | tmp_date = date
26 | while True:
27 | tmp_date += datetime.timedelta(days=-1)
28 | if tmp_date in trade_date:
29 | break
30 | return tmp_date
31 |
32 |
33 | def get_next_trade_date(date):
34 | trade_date = stock_trade_date().get_data()
35 | if trade_date is None:
36 | return date
37 | tmp_date = date
38 | while True:
39 | tmp_date += datetime.timedelta(days=1)
40 | if tmp_date in trade_date:
41 | break
42 | return tmp_date
43 |
44 |
45 | OPEN_TIME = (
46 | (datetime.time(9, 15, 0), datetime.time(11, 30, 0)),
47 | (datetime.time(13, 0, 0), datetime.time(15, 0, 0)),
48 | )
49 |
50 |
51 | def is_tradetime(now_time):
52 | now = now_time.time()
53 | for begin, end in OPEN_TIME:
54 | if begin <= now < end:
55 | return True
56 | else:
57 | return False
58 |
59 |
60 | PAUSE_TIME = (
61 | (datetime.time(11, 30, 0), datetime.time(12, 59, 30)),
62 | )
63 |
64 |
65 | def is_pause(now_time):
66 | now = now_time.time()
67 | for b, e in PAUSE_TIME:
68 | if b <= now < e:
69 | return True
70 |
71 |
72 | CONTINUE_TIME = (
73 | (datetime.time(12, 59, 30), datetime.time(13, 0, 0)),
74 | )
75 |
76 |
77 | def is_continue(now_time):
78 | now = now_time.time()
79 | for b, e in CONTINUE_TIME:
80 | if b <= now < e:
81 | return True
82 | return False
83 |
84 |
85 | CLOSE_TIME = (
86 | datetime.time(15, 0, 0),
87 | )
88 |
89 |
90 | def is_closing(now_time, start=datetime.time(14, 54, 30)):
91 | now = now_time.time()
92 | for close in CLOSE_TIME:
93 | if start <= now < close:
94 | return True
95 | return False
96 |
97 |
98 | def is_close(now_time):
99 | now = now_time.time()
100 | for close in CLOSE_TIME:
101 | if now >= close:
102 | return True
103 | return False
104 |
105 |
106 | def is_open(now_time):
107 | now = now_time.time()
108 | if now >= datetime.time(9, 30, 0):
109 | return True
110 | return False
111 |
112 |
113 | def get_trade_hist_interval(date):
114 | tmp_year, tmp_month, tmp_day = date.split("-")
115 | date_end = datetime.datetime(int(tmp_year), int(tmp_month), int(tmp_day))
116 | date_start = (date_end + datetime.timedelta(days=-(365 * 3))).strftime("%Y%m%d")
117 |
118 | now_time = datetime.datetime.now()
119 | now_date = now_time.date()
120 | is_trade_date_open_close_between = False
121 | if date_end.date() == now_date:
122 | if is_trade_date(now_date):
123 | if is_open(now_time) and not is_close(now_time):
124 | is_trade_date_open_close_between = True
125 |
126 | return date_start, not is_trade_date_open_close_between
127 |
128 |
129 | def get_trade_date_last():
130 | now_time = datetime.datetime.now()
131 | run_date = now_time.date()
132 | run_date_nph = run_date
133 | if is_trade_date(run_date):
134 | if not is_close(now_time):
135 | run_date = get_previous_trade_date(run_date)
136 | if not is_open(now_time):
137 | run_date_nph = run_date
138 | else:
139 | run_date = get_previous_trade_date(run_date)
140 | run_date_nph = run_date
141 | return run_date, run_date_nph
142 |
143 |
144 | def get_quarterly_report_date():
145 | now_time = datetime.datetime.now()
146 | year = now_time.year
147 | month = now_time.month
148 | if 1 <= month <= 3:
149 | month_day = '1231'
150 | elif 4 <= month <= 6:
151 | month_day = '0331'
152 | elif 7 <= month <= 9:
153 | month_day = '0630'
154 | else:
155 | month_day = '0930'
156 | return f"{year}{month_day}"
157 |
158 |
159 | def get_bonus_report_date():
160 | now_time = datetime.datetime.now()
161 | year = now_time.year
162 | month = now_time.month
163 | if 2 <= month <= 6:
164 | year -= 1
165 | month_day = '1231'
166 | elif 8 <= month <= 12:
167 | month_day = '0630'
168 | elif month == 7:
169 | if now_time.day > 25:
170 | month_day = '0630'
171 | else:
172 | year -= 1
173 | month_day = '1231'
174 | else:
175 | year -= 1
176 | if now_time.day > 25:
177 | month_day = '1231'
178 | else:
179 | month_day = '0630'
180 | return f"{year}{month_day}"
181 |
--------------------------------------------------------------------------------
/instock/core/crawling/stock_cpbd.py:
--------------------------------------------------------------------------------
1 | # -*- coding:utf-8 -*-
2 | # !/usr/bin/env python
3 |
4 | import pandas as pd
5 | import requests
6 | import instock.core.tablestructure as tbs
7 |
8 | __author__ = 'myh '
9 | __date__ = '2023/5/7 '
10 |
11 |
12 |
13 | def stock_cpbd_em(symbol: str = "688041") -> pd.DataFrame:
14 | """
15 | 东方财富网-个股-操盘必读
16 | https://emweb.securities.eastmoney.com/PC_HSF10/OperationsRequired/Index?type=web&code=SH688041#
17 | :param symbol: 带市场标识的股票代码
18 | :type symbol: str
19 | :return: 操盘必读
20 | :rtype: pandas.DataFrame
21 | """
22 | url = "https://emweb.securities.eastmoney.com/PC_HSF10/OperationsRequired/PageAjax"
23 | if symbol.startswith("6"):
24 | symbol = f"SH{symbol}"
25 | else:
26 | symbol = f"SZ{symbol}"
27 | params = {"code": symbol}
28 |
29 | r = requests.get(url, params=params)
30 | data_json = r.json()
31 | zxzb = data_json["zxzb"] # 主要指标
32 | if len(zxzb) < 1:
33 | return None
34 |
35 | data_dict = zxzb[0]
36 | zxzbOther = data_json["zxzbOther"] # 其它指标,计算出来
37 | if len(zxzbOther) > 0:
38 | zxzbOther = zxzbOther[0]
39 | data_dict = {**data_dict, **zxzbOther}
40 |
41 | # zxzbhq = data_json["zxzbhq"] # 其它指标,计算出来
42 | # if len(zxzbhq) > 0:
43 | # data_dict = {**data_dict, **zxzbhq}
44 |
45 | _ssbks = data_json["ssbk"] # 所属板块
46 | ssbk = None
47 | for s in _ssbks:
48 | _v = s.get('BOARD_NAME')
49 | if _v is not None:
50 | if ssbk is None:
51 | ssbk = f"{_v}"
52 | else:
53 | ssbk = f"{ssbk}、{_v}"
54 | data_dict["BOARD_NAME"] = ssbk
55 |
56 | gdrs = data_json["gdrs"] # 股东分析
57 | if len(gdrs) > 0:
58 | gdrs = gdrs[0]
59 | data_dict = {**data_dict, **gdrs}
60 |
61 | lhbd = data_json["lhbd"] # 龙虎榜单
62 | if len(lhbd) > 0:
63 | lhbd = lhbd[0]
64 | lhbd["LHBD_DATE"] = lhbd.pop("TRADE_DATE")
65 | data_dict = {**data_dict, **lhbd}
66 |
67 | dzjy = data_json["dzjy"] # 大宗交易
68 | if len(dzjy) > 0:
69 | dzjy = dzjy[0]
70 | dzjy["DZJY_DATE"] = dzjy.pop("TRADE_DATE")
71 | data_dict = {**data_dict, **dzjy}
72 |
73 | rzrq = data_json["rzrq"] # 融资融券
74 | if len(rzrq) > 0:
75 | rzrq = rzrq[0]
76 | rzrq["RZRQ_DATE"] = rzrq.pop("TRADE_DATE")
77 | data_dict = {**data_dict, **rzrq}
78 |
79 | tbs.CN_STOCK_CPBD
80 |
81 |
82 | # temp_df["报告期"] = pd.to_datetime(temp_df["报告期"], errors="coerce").dt.date
83 | # temp_df["每股收益"] = pd.to_numeric(temp_df["每股收益"], errors="coerce")
84 | # temp_df["每股净资产"] = pd.to_numeric(temp_df["每股净资产"], errors="coerce")
85 | # temp_df["每股经营现金流"] = pd.to_numeric(temp_df["每股经营现金流"], errors="coerce")
86 | # temp_df["每股公积金"] = pd.to_numeric(temp_df["每股公积金"], errors="coerce")
87 | # temp_df["每股未分配利润"] = pd.to_numeric(temp_df["每股未分配利润"], errors="coerce")
88 | # temp_df["加权净资产收益率"] = pd.to_numeric(temp_df["加权净资产收益率"], errors="coerce")
89 | # temp_df["毛利率"] = pd.to_numeric(temp_df["毛利率"], errors="coerce")
90 | # temp_df["资产负债率"] = pd.to_numeric(temp_df["资产负债率"], errors="coerce")
91 | # temp_df["营业收入"] = pd.to_numeric(temp_df["营业收入"], errors="coerce")
92 | # temp_df["营业收入滚动环比增长"] = pd.to_numeric(temp_df["营业收入同比增长"], errors="coerce")
93 | # temp_df["营业收入同比增长"] = pd.to_numeric(temp_df["营业收入同比增长"], errors="coerce")
94 | # temp_df["归属净利润"] = pd.to_numeric(temp_df["归属净利润"], errors="coerce")
95 | # temp_df["归属净利润滚动环比增长"] = pd.to_numeric(temp_df["归属净利润滚动环比增长"], errors="coerce")
96 | # temp_df["归属净利润同比增长"] = pd.to_numeric(temp_df["归属净利润同比增长"], errors="coerce")
97 | # temp_df["扣非净利润"] = pd.to_numeric(temp_df["归属净利润"], errors="coerce")
98 | # temp_df["扣非净利润滚动环比增长"] = pd.to_numeric(temp_df["扣非净利润滚动环比增长"], errors="coerce")
99 | # temp_df["扣非净利润同比增长"] = pd.to_numeric(temp_df["扣非净利润同比增长"], errors="coerce")
100 | # temp_df["总股本"] = pd.to_numeric(temp_df["总股本"], errors="coerce")
101 | # temp_df["已流通股份"] = pd.to_numeric(temp_df["已流通股份"], errors="coerce")
102 |
103 |
104 | def stock_zjlx_em(symbol: str = "688041") -> pd.DataFrame:
105 | """
106 | 东方财富网-个股-资金流向
107 | https://data.eastmoney.com/zjlx/688041.html
108 | :param symbol: 带市场标识的股票代码
109 | :type symbol: str
110 | :return: 操盘必读
111 | :rtype: pandas.DataFrame
112 | """
113 | url = "https://push2his.eastmoney.com/api/qt/stock/fflow/daykline/get"
114 | if symbol.startswith("6"):
115 | symbol = f"1.{symbol}"
116 | else:
117 | symbol = f"0.{symbol}"
118 | params = {
119 | "lmt": "0",
120 | "klt": "1",
121 | "fields1": "f1,f2,f3,f7",
122 | "fields2": "f51,f52,f53,f54,f55,f56,f57,f58,f59,f60,f61,f62,f63,f64,f65",
123 | "ut": "b2884a393a59ad64002292a3e90d46a5",
124 | "secid": symbol
125 | }
126 |
127 | r = requests.get(url, params=params)
128 | data_json = r.json()
129 | klines = data_json["klines"] # 主要指标
130 | "日期","主力净流入额","小单净流入额","中单净流入额","大单净流入额","超大单净流入额","主力净流入占比", "小单净流入占比", "中单净流入占比", "大单净流入占比", "超大单净流入占比"
131 | "收盘价","涨跌幅"
132 | if len(klines) < 1:
133 | return None
134 |
135 |
136 |
137 | if __name__ == "__main__":
138 | stock_cpbd_em_df = stock_cpbd_em(symbol="688041")
139 | print(stock_cpbd_em_df)
140 |
--------------------------------------------------------------------------------
/instock/web/static/js/ace-extra.min.js:
--------------------------------------------------------------------------------
1 | !function(){"ace"in window||(window.ace={}),ace.config={storage_method:0,cookie_expiry:604800,cookie_path:""},"vars"in window.ace||(window.ace.vars={}),ace.vars.very_old_ie=!("querySelector"in document.documentElement),ace.settings={saveState:function(a,b,c,d){if(!a||"string"==typeof a&&!(a=document.getElementById(a))||!a.hasAttribute("id"))return!1;if(!ace.hasClass(a,"ace-save-state"))return!1;var b=b||"class",e=a.getAttribute("id"),f=ace.data.get("state","id-"+e)||{};if("string"==typeof f)try{f=JSON.parse(f)}catch(g){f={}}var h,i="undefined"!=typeof c,j=!1,k=/class/i,l=/checked|disabled|readonly|value/i;l.test(b)?h=i?c:a[b]:a.hasAttribute(b)?h=i?c:a.getAttribute(b):i||(j=!0),j?delete f[b]:k.test(b)?(f.hasOwnProperty(b)||(f[b]={}),d===!0?f[b][h]=1:d===!1?f[b][h]=-1:f[b].className=h):f[b]=h,ace.data.set("state","id-"+e,JSON.stringify(f))},loadState:function(a,b){if(!a||"string"==typeof a&&!(a=document.getElementById(a))||!a.hasAttribute("id"))return!1;var c=a.getAttribute("id"),d=ace.data.get("state","id-"+c)||{};if("string"==typeof d)try{d=JSON.parse(d)}catch(e){d={}}var f=function(a,b,c){var d=/class/i,e=/checked|disabled|readonly|value/i;if(d.test(b)){if("object"==typeof c){"className"in c&&a.setAttribute("class",c.className);for(var f in c)if(c.hasOwnProperty(f)){var g=c[f];1==g?ace.addClass(a,f):-1==g&&ace.removeClass(a,f)}}}else e.test(b)?a[b]=c:a.setAttribute(b,c)};if(void 0!==b)d.hasOwnProperty(b)&&null!==d[b]&&f(a,b,d[b]);else for(var g in d)d.hasOwnProperty(g)&&null!==d[g]&&f(a,g,d[g])},clearState:function(a){var b=null;"string"==typeof a?b=a:"hasAttribute"in a&&a.hasAttribute("id")&&(b=a.getAttribute("id")),b&&ace.data.remove("state","id-"+b)}},function(){var a=function(){var a=!1,b="animation",c="",d="Webkit Moz O ms Khtml".split(" "),e="",f=document.createElement("div");if(void 0!==f.style.animationName&&(a=!0),a===!1)for(var g=0;g-1},ace.addClass=function(a,b){for(var c=b.split(/\s+/),d=0;d0&&!ace.hasClass(a,c[d])){var e=a.className;a.className=e+(e.length?" ":"")+c[d]}},ace.removeClass=function(a,b){for(var c=b.split(/\s+/),d=0;d0&&ace.replaceClass(a,c[d]);ace.replaceClass(a,b)},ace.replaceClass=function(a,b,c){var d=new RegExp("(^|\\s)"+b+"(\\s|$)","i");a.className=a.className.replace(d,function(a,b,d){return c?b+c+d:" "}).replace(/^\s+|\s+$/g,"")},ace.toggleClass=function(a,b){ace.hasClass(a,b)?ace.removeClass(a,b):ace.addClass(a,b)},ace.isHTMlElement=function(a){return window.HTMLElement?a instanceof HTMLElement:"nodeType"in a?1==a.nodeType:!1},ace.data=new ace.data_storage(ace.config.storage_method)}();
--------------------------------------------------------------------------------
/instock/web/static/js/FileSaver.js:
--------------------------------------------------------------------------------
1 | /*
2 | * FileSaver.js
3 | * A saveAs() FileSaver implementation.
4 | *
5 | * By Eli Grey, http://eligrey.com
6 | *
7 | * License : https://github.com/eligrey/FileSaver.js/blob/master/LICENSE.md (MIT)
8 | * source : http://purl.eligrey.com/github/FileSaver.js
9 | */
10 |
11 | // The one and only way of getting global scope in all environments
12 | // https://stackoverflow.com/q/3277182/1008999
13 | var _global = typeof window === 'object' && window.window === window
14 | ? window : typeof self === 'object' && self.self === self
15 | ? self : typeof global === 'object' && global.global === global
16 | ? global
17 | : this
18 |
19 | function bom (blob, opts) {
20 | if (typeof opts === 'undefined') opts = { autoBom: false }
21 | else if (typeof opts !== 'object') {
22 | console.warn('Deprecated: Expected third argument to be a object')
23 | opts = { autoBom: !opts }
24 | }
25 |
26 | // prepend BOM for UTF-8 XML and text/* types (including HTML)
27 | // note: your browser will automatically convert UTF-16 U+FEFF to EF BB BF
28 | if (opts.autoBom && /^\s*(?:text\/\S*|application\/xml|\S*\/\S*\+xml)\s*;.*charset\s*=\s*utf-8/i.test(blob.type)) {
29 | return new Blob([String.fromCharCode(0xFEFF), blob], { type: blob.type })
30 | }
31 | return blob
32 | }
33 |
34 | function download (url, name, opts) {
35 | var xhr = new XMLHttpRequest()
36 | xhr.open('GET', url)
37 | xhr.responseType = 'blob'
38 | xhr.onload = function () {
39 | saveAs(xhr.response, name, opts)
40 | }
41 | xhr.onerror = function () {
42 | console.error('could not download file')
43 | }
44 | xhr.send()
45 | }
46 |
47 | function corsEnabled (url) {
48 | var xhr = new XMLHttpRequest()
49 | // use sync to avoid popup blocker
50 | xhr.open('HEAD', url, false)
51 | try {
52 | xhr.send()
53 | } catch (e) {}
54 | return xhr.status >= 200 && xhr.status <= 299
55 | }
56 |
57 | // `a.click()` doesn't work for all browsers (#465)
58 | function click (node) {
59 | try {
60 | node.dispatchEvent(new MouseEvent('click'))
61 | } catch (e) {
62 | var evt = document.createEvent('MouseEvents')
63 | evt.initMouseEvent('click', true, true, window, 0, 0, 0, 80,
64 | 20, false, false, false, false, 0, null)
65 | node.dispatchEvent(evt)
66 | }
67 | }
68 |
69 | // Detect WebView inside a native macOS app by ruling out all browsers
70 | // We just need to check for 'Safari' because all other browsers (besides Firefox) include that too
71 | // https://www.whatismybrowser.com/guides/the-latest-user-agent/macos
72 | var isMacOSWebView = /Macintosh/.test(navigator.userAgent) && /AppleWebKit/.test(navigator.userAgent) && !/Safari/.test(navigator.userAgent)
73 |
74 | var saveAs = _global.saveAs || (
75 | // probably in some web worker
76 | (typeof window !== 'object' || window !== _global)
77 | ? function saveAs () { /* noop */ }
78 |
79 | // Use download attribute first if possible (#193 Lumia mobile) unless this is a macOS WebView
80 | : ('download' in HTMLAnchorElement.prototype && !isMacOSWebView)
81 | ? function saveAs (blob, name, opts) {
82 | var URL = _global.URL || _global.webkitURL
83 | var a = document.createElement('a')
84 | name = name || blob.name || 'download'
85 |
86 | a.download = name
87 | a.rel = 'noopener' // tabnabbing
88 |
89 | // TODO: detect chrome extensions & packaged apps
90 | // a.target = '_blank'
91 |
92 | if (typeof blob === 'string') {
93 | // Support regular links
94 | a.href = blob
95 | if (a.origin !== location.origin) {
96 | corsEnabled(a.href)
97 | ? download(blob, name, opts)
98 | : click(a, a.target = '_blank')
99 | } else {
100 | click(a)
101 | }
102 | } else {
103 | // Support blobs
104 | a.href = URL.createObjectURL(blob)
105 | setTimeout(function () { URL.revokeObjectURL(a.href) }, 4E4) // 40s
106 | setTimeout(function () { click(a) }, 0)
107 | }
108 | }
109 |
110 | // Use msSaveOrOpenBlob as a second approach
111 | : 'msSaveOrOpenBlob' in navigator
112 | ? function saveAs (blob, name, opts) {
113 | name = name || blob.name || 'download'
114 |
115 | if (typeof blob === 'string') {
116 | if (corsEnabled(blob)) {
117 | download(blob, name, opts)
118 | } else {
119 | var a = document.createElement('a')
120 | a.href = blob
121 | a.target = '_blank'
122 | setTimeout(function () { click(a) })
123 | }
124 | } else {
125 | navigator.msSaveOrOpenBlob(bom(blob, opts), name)
126 | }
127 | }
128 |
129 | // Fallback to using FileReader and a popup
130 | : function saveAs (blob, name, opts, popup) {
131 | // Open a popup immediately do go around popup blocker
132 | // Mostly only available on user interaction and the fileReader is async so...
133 | popup = popup || open('', '_blank')
134 | if (popup) {
135 | popup.document.title =
136 | popup.document.body.innerText = 'downloading...'
137 | }
138 |
139 | if (typeof blob === 'string') return download(blob, name, opts)
140 |
141 | var force = blob.type === 'application/octet-stream'
142 | var isSafari = /constructor/i.test(_global.HTMLElement) || _global.safari
143 | var isChromeIOS = /CriOS\/[\d]+/.test(navigator.userAgent)
144 |
145 | if ((isChromeIOS || (force && isSafari) || isMacOSWebView) && typeof FileReader !== 'undefined') {
146 | // Safari doesn't allow downloading of blob URLs
147 | var reader = new FileReader()
148 | reader.onloadend = function () {
149 | var url = reader.result
150 | url = isChromeIOS ? url : url.replace(/^data:[^;]*;/, 'data:attachment/file;')
151 | if (popup) popup.location.href = url
152 | else location = url
153 | popup = null // reverse-tabnabbing #460
154 | }
155 | reader.readAsDataURL(blob)
156 | } else {
157 | var URL = _global.URL || _global.webkitURL
158 | var url = URL.createObjectURL(blob)
159 | if (popup) popup.location = url
160 | else location.href = url
161 | popup = null // reverse-tabnabbing #460
162 | setTimeout(function () { URL.revokeObjectURL(url) }, 4E4) // 40s
163 | }
164 | }
165 | )
166 |
167 | _global.saveAs = saveAs.saveAs = saveAs
168 |
169 | if (typeof module !== 'undefined') {
170 | module.exports = saveAs;
171 | }
172 |
--------------------------------------------------------------------------------
/instock/core/kline/cyq.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | # -*- coding: utf-8 -*-
3 |
4 | __author__ = 'myh '
5 | __date__ = '2025/1/6 '
6 |
7 |
8 | # * 筹码分布算法
9 | # * @param {Array.>} kdata K图数据 [date,open,close,high,low,volume,amount,amplitude,turnover]
10 | # * @param {number} [accuracyFactor=500] 精度因子
11 | # * @param {number} [range] 计算范围
12 | # * @param {number} [cyq_days] 计算交易天数
13 | class CYQCalculator:
14 | def __init__(self, kdata, accuracy_factor=150, crange=120, cyq_days=210):
15 | # K图数据
16 | self.klinedata = kdata
17 | # 精度因子(纵轴刻度数)
18 | self.fator = accuracy_factor
19 | # 计算K线条数
20 | self.range = crange
21 | # 计算筹码分布的交易天数
22 | self.tradingdays = cyq_days
23 |
24 | # *计算分布及相关指标
25 | # * @ param {number} index 当前选中的K线的索引
26 | # * @ return {{x: Array. < number >, y: Array. < number >}}
27 | def calc(self, index):
28 | maxprice = 0
29 | minprice = 1000000
30 | factor = self.fator
31 | end = index - self.range + 1
32 | start = end - self.tradingdays
33 |
34 | if end == 0:
35 | kdata = self.klinedata.tail(self.tradingdays)
36 | else:
37 | kdata = self.klinedata[start:end]
38 |
39 | for _high, _low in zip(kdata['high'].values, kdata['low'].values):
40 | maxprice = max(maxprice, _high)
41 | minprice = min(minprice, _low)
42 |
43 | # 精度不小于0.01产品逻辑
44 | accuracy = max(0.01, (maxprice - minprice) / (factor - 1))
45 | currentprice = kdata.iloc[-1]['close']
46 | boundary = -1
47 |
48 | # *值域 @ type {Array. < number >}
49 | yrange = []
50 |
51 | for i in range(factor):
52 | _price = float(f"{minprice + accuracy * i:.2f}")
53 | yrange.append(_price)
54 | if boundary == -1 and _price >= currentprice:
55 | boundary = i
56 |
57 | # *横轴数据
58 | xdata = [0] * factor
59 |
60 | for open_price, close, high, low, turnover in zip(kdata['open'].values, kdata['close'].values, kdata['high'].values, kdata['low'].values, kdata['turnover'].values):
61 | avg = (open_price + close + high + low) / 4
62 | turnover_rate = min(1, turnover / 100)
63 |
64 | H = int((high - minprice) / accuracy)
65 | L = int((low - minprice) / accuracy + 0.99)
66 | # G点坐标, 一字板时, X为进度因子
67 | GPoint = [factor - 1 if high == low else 2 / (high - low),
68 | int((avg - minprice) / accuracy)]
69 |
70 | for n in range(len(xdata)):
71 | xdata[n] *= (1 - turnover_rate)
72 |
73 | if high == low:
74 | # 一字板时,画矩形面积是三角形的2倍
75 | xdata[GPoint[1]] += GPoint[0] * turnover_rate / 2
76 | else:
77 | for j in range(L, H + 1):
78 | curprice = minprice + accuracy * j
79 | if curprice <= avg:
80 | # 上半三角叠加分布分布
81 | if abs(avg - low) < 1e-8:
82 | xdata[j] += GPoint[0] * turnover_rate
83 | else:
84 | xdata[j] += (curprice - low) / (avg - low) * GPoint[0] * turnover_rate
85 | else:
86 | # 下半三角叠加分布分布
87 | if abs(high - avg) < 1e-8:
88 | xdata[j] += GPoint[0] * turnover_rate
89 | else:
90 | xdata[j] += (high - curprice) / (high - avg) * GPoint[0] * turnover_rate
91 |
92 | total_chips = sum(float(f"{x:.12g}") for x in xdata)
93 |
94 | # *获取指定筹码处的成本
95 | # * @ param {number} chip 堆叠筹码
96 | def get_cost_by_chip(chip):
97 | result = 0
98 | sum_chips = 0
99 | for i in range(factor):
100 | x = float(f"{xdata[i]:.12g}")
101 | if sum_chips + x > chip:
102 | result = minprice + i * accuracy
103 | break
104 | sum_chips += x
105 | return result
106 |
107 | # *筹码分布数据
108 | class CYQData:
109 | def __init__(self):
110 | # 筹码堆叠
111 | self.x = None
112 | # 价格分布
113 | self.y = None
114 | # 获利比例
115 | self.benefit_part = None
116 | # 平均成本
117 | self.avg_cost = None
118 | # 百分比筹码
119 | self.percent_chips = None
120 | # 筹码堆叠亏盈分界下标
121 | self.b = None
122 | # 交易日期
123 | self.d = None
124 | # 交易天数
125 | self.t = None
126 |
127 | # *计算指定百分比的筹码
128 | # * @ param {number} percent 百分比大于0,小于1
129 | @staticmethod
130 | def compute_percent_chips(percent):
131 | if percent > 1 or percent < 0:
132 | raise ValueError('argument "percent" out of range')
133 | ps = [(1 - percent) / 2, (1 + percent) / 2]
134 | pr = [get_cost_by_chip(total_chips * ps[0]),
135 | get_cost_by_chip(total_chips * ps[1])]
136 | return {
137 | 'priceRange': [f"{pr[0]:.2f}", f"{pr[1]:.2f}"],
138 | 'concentration': 0 if pr[0] + pr[1] == 0 else (pr[1] - pr[0]) / (pr[0] + pr[1])
139 | }
140 |
141 | # *获取指定价格的获利比例
142 | # * @ param {number} price 价格
143 | @staticmethod
144 | def get_benefit_part(price):
145 | below = 0
146 | for i in range(factor):
147 | x = float(f"{xdata[i]:.12g}")
148 | if price >= minprice + i * accuracy:
149 | below += x
150 | return 0 if total_chips == 0 else below / total_chips
151 |
152 | result = CYQData()
153 | result.x = xdata
154 | result.y = yrange
155 | result.b = boundary + 1
156 | result.d = kdata.iloc[-1]['date']
157 | result.t = self.tradingdays
158 | result.benefit_part = result.get_benefit_part(currentprice)
159 | result.avg_cost = f"{get_cost_by_chip(total_chips * 0.5):.2f}"
160 | result.percent_chips = {
161 | '90': result.compute_percent_chips(0.9),
162 | '70': result.compute_percent_chips(0.7)
163 | }
164 |
165 | return result
166 |
167 | # if __name__ == "__main__":
168 | # # import instock.core.kline.cyq as cyq
169 | # # c = cyq.CYQCalculator(cyq_stock)
170 | # # r = c.calc(119)
--------------------------------------------------------------------------------
/instock/job/indicators_data_daily_job.py:
--------------------------------------------------------------------------------
1 | #!/usr/local/bin/python3
2 | # -*- coding: utf-8 -*-
3 |
4 |
5 | import logging
6 | import concurrent.futures
7 | import pandas as pd
8 | import os.path
9 | import sys
10 |
11 | cpath_current = os.path.dirname(os.path.dirname(__file__))
12 | cpath = os.path.abspath(os.path.join(cpath_current, os.pardir))
13 | sys.path.append(cpath)
14 | import instock.lib.run_template as runt
15 | import instock.core.tablestructure as tbs
16 | import instock.lib.database as mdb
17 | import instock.core.indicator.calculate_indicator as idr
18 | from instock.core.singleton_stock import stock_hist_data
19 |
20 | __author__ = 'myh '
21 | __date__ = '2023/3/10 '
22 |
23 |
24 | def prepare(date):
25 | try:
26 | stocks_data = stock_hist_data(date=date).get_data()
27 | if stocks_data is None:
28 | return
29 | results = run_check(stocks_data, date=date)
30 | if results is None:
31 | return
32 |
33 | table_name = tbs.TABLE_CN_STOCK_INDICATORS['name']
34 | # 删除老数据。
35 | if mdb.checkTableIsExist(table_name):
36 | del_sql = f"DELETE FROM `{table_name}` where `date` = '{date}'"
37 | mdb.executeSql(del_sql)
38 | cols_type = None
39 | else:
40 | cols_type = tbs.get_field_types(tbs.TABLE_CN_STOCK_INDICATORS['columns'])
41 |
42 | dataKey = pd.DataFrame(results.keys())
43 | _columns = tuple(tbs.TABLE_CN_STOCK_FOREIGN_KEY['columns'])
44 | dataKey.columns = _columns
45 |
46 | dataVal = pd.DataFrame(results.values())
47 | dataVal.drop('date', axis=1, inplace=True) # 删除日期字段,然后和原始数据合并。
48 |
49 | data = pd.merge(dataKey, dataVal, on=['code'], how='left')
50 | # data.set_index('code', inplace=True)
51 | # 单例,时间段循环必须改时间
52 | date_str = date.strftime("%Y-%m-%d")
53 | if date.strftime("%Y-%m-%d") != data.iloc[0]['date']:
54 | data['date'] = date_str
55 | mdb.insert_db_from_df(data, table_name, cols_type, False, "`date`,`code`")
56 |
57 | except Exception as e:
58 | logging.error(f"indicators_data_daily_job.prepare处理异常:{e}")
59 |
60 |
61 | def run_check(stocks, date=None, workers=40):
62 | data = {}
63 | columns = list(tbs.STOCK_STATS_DATA['columns'])
64 | columns.insert(0, 'code')
65 | columns.insert(0, 'date')
66 | data_column = columns
67 | try:
68 | with concurrent.futures.ThreadPoolExecutor(max_workers=workers) as executor:
69 | future_to_data = {executor.submit(idr.get_indicator, k, stocks[k], data_column, date=date): k for k in stocks}
70 | for future in concurrent.futures.as_completed(future_to_data):
71 | stock = future_to_data[future]
72 | try:
73 | _data_ = future.result()
74 | if _data_ is not None:
75 | data[stock] = _data_
76 | except Exception as e:
77 | logging.error(f"indicators_data_daily_job.run_check处理异常:{stock[1]}代码{e}")
78 | except Exception as e:
79 | logging.error(f"indicators_data_daily_job.run_check处理异常:{e}")
80 | if not data:
81 | return None
82 | else:
83 | return data
84 |
85 |
86 | # 对每日指标数据,进行筛选。将符合条件的。二次筛选出来。
87 | # 只是做简单筛选
88 | def guess_buy(date):
89 | try:
90 | _table_name = tbs.TABLE_CN_STOCK_INDICATORS['name']
91 | if not mdb.checkTableIsExist(_table_name):
92 | return
93 |
94 | _columns = tuple(tbs.TABLE_CN_STOCK_FOREIGN_KEY['columns'])
95 | _selcol = '`,`'.join(_columns)
96 | sql = f'''SELECT `{_selcol}` FROM `{_table_name}` WHERE `date` = '{date}' and
97 | `kdjk` >= 80 and `kdjd` >= 70 and `kdjj` >= 100 and `rsi_6` >= 80 and
98 | `cci` >= 100 and `cr` >= 300 and `wr_6` >= -20 and `vr` >= 160'''
99 | data = pd.read_sql(sql=sql, con=mdb.engine())
100 | data = data.drop_duplicates(subset="code", keep="last")
101 | # data.set_index('code', inplace=True)
102 |
103 | if len(data.index) == 0:
104 | return
105 |
106 | table_name = tbs.TABLE_CN_STOCK_INDICATORS_BUY['name']
107 | # 删除老数据。
108 | if mdb.checkTableIsExist(table_name):
109 | del_sql = f"DELETE FROM `{table_name}` where `date` = '{date}'"
110 | mdb.executeSql(del_sql)
111 | cols_type = None
112 | else:
113 | cols_type = tbs.get_field_types(tbs.TABLE_CN_STOCK_INDICATORS_BUY['columns'])
114 |
115 | _columns_backtest = tuple(tbs.TABLE_CN_STOCK_BACKTEST_DATA['columns'])
116 | data = pd.concat([data, pd.DataFrame(columns=_columns_backtest)])
117 | mdb.insert_db_from_df(data, table_name, cols_type, False, "`date`,`code`")
118 | except Exception as e:
119 | logging.error(f"indicators_data_daily_job.guess_buy处理异常:{e}")
120 |
121 |
122 | # 设置卖出数据。
123 | def guess_sell(date):
124 | try:
125 | _table_name = tbs.TABLE_CN_STOCK_INDICATORS['name']
126 | if not mdb.checkTableIsExist(_table_name):
127 | return
128 |
129 | _columns = tuple(tbs.TABLE_CN_STOCK_FOREIGN_KEY['columns'])
130 | _selcol = '`,`'.join(_columns)
131 | sql = f'''SELECT `{_selcol}` FROM `{_table_name}` WHERE `date` = '{date}' and
132 | `kdjk` < 20 and `kdjd` < 30 and `kdjj` < 10 and `rsi_6` < 20 and
133 | `cci` < -100 and `cr` < 40 and `wr_6` < -80 and `vr` < 40'''
134 | data = pd.read_sql(sql=sql, con=mdb.engine())
135 | data = data.drop_duplicates(subset="code", keep="last")
136 | # data.set_index('code', inplace=True)
137 | if len(data.index) == 0:
138 | return
139 |
140 | table_name = tbs.TABLE_CN_STOCK_INDICATORS_SELL['name']
141 | # 删除老数据。
142 | if mdb.checkTableIsExist(table_name):
143 | del_sql = f"DELETE FROM `{table_name}` where `date` = '{date}'"
144 | mdb.executeSql(del_sql)
145 | cols_type = None
146 | else:
147 | cols_type = tbs.get_field_types(tbs.TABLE_CN_STOCK_INDICATORS_SELL['columns'])
148 |
149 | _columns_backtest = tuple(tbs.TABLE_CN_STOCK_BACKTEST_DATA['columns'])
150 | data = pd.concat([data, pd.DataFrame(columns=_columns_backtest)])
151 | mdb.insert_db_from_df(data, table_name, cols_type, False, "`date`,`code`")
152 | except Exception as e:
153 | logging.error(f"indicators_data_daily_job.guess_sell处理异常:{e}")
154 |
155 |
156 | def main():
157 | # 使用方法传递。
158 | runt.run_with_args(prepare)
159 | # 二次筛选数据。直接计算买卖股票数据。
160 | runt.run_with_args(guess_buy)
161 | runt.run_with_args(guess_sell)
162 |
163 |
164 | # main函数入口
165 | if __name__ == '__main__':
166 | main()
167 |
--------------------------------------------------------------------------------
/instock/lib/crypto_aes.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | # -*- coding: utf-8 -*-
3 |
4 | from Crypto.Cipher import AES
5 | import base64
6 | import binascii
7 |
8 | __author__ = 'myh '
9 | __date__ = '2023/3/10 '
10 |
11 |
12 | # 数据类
13 | class MData():
14 | def __init__(self, data=b"", characterSet='utf-8'):
15 | # data肯定为bytes
16 | self.data = data
17 | self.characterSet = characterSet
18 |
19 | def saveData(self, FileName):
20 | with open(FileName, 'wb') as f:
21 | f.write(self.data)
22 |
23 | def fromString(self, data):
24 | self.data = data.encode(self.characterSet)
25 | return self.data
26 |
27 | def fromBase64(self, data):
28 | self.data = base64.b64decode(data.encode(self.characterSet))
29 | return self.data
30 |
31 | def fromHexStr(self, data):
32 | self.data = binascii.a2b_hex(data)
33 | return self.data
34 |
35 | def toString(self):
36 | return self.data.decode(self.characterSet)
37 |
38 | def toBase64(self):
39 | return base64.b64encode(self.data).decode()
40 |
41 | def toHexStr(self):
42 | return binascii.b2a_hex(self.data).decode()
43 |
44 | def toBytes(self):
45 | return self.data
46 |
47 | def __str__(self):
48 | try:
49 | return self.toString()
50 | except Exception:
51 | return self.toBase64()
52 |
53 |
54 | ### 封装类
55 | class AEScryptor():
56 | def __init__(self, key, mode, iv='', paddingMode="NoPadding", characterSet="utf-8"):
57 | '''
58 | 构建一个AES对象
59 | key: 秘钥,字节型数据
60 | mode: 使用模式,只提供两种,AES.MODE_CBC, AES.MODE_ECB
61 | iv: iv偏移量,字节型数据
62 | paddingMode: 填充模式,默认为NoPadding, 可选NoPadding,ZeroPadding,PKCS5Padding,PKCS7Padding
63 | characterSet: 字符集编码
64 | '''
65 | self.key = key
66 | self.mode = mode
67 | self.iv = iv
68 | self.characterSet = characterSet
69 | self.paddingMode = paddingMode
70 | self.data = ""
71 |
72 | def __ZeroPadding(self, data):
73 | data += b'\x00'
74 | while len(data) % 16 != 0:
75 | data += b'\x00'
76 | return data
77 |
78 | def __StripZeroPadding(self, data):
79 | data = data[:-1]
80 | while len(data) % 16 != 0:
81 | data = data.rstrip(b'\x00')
82 | if data[-1] != b"\x00":
83 | break
84 | return data
85 |
86 | def __PKCS5_7Padding(self, data):
87 | needSize = 16 - len(data) % 16
88 | if needSize == 0:
89 | needSize = 16
90 | return data + needSize.to_bytes(1, 'little') * needSize
91 |
92 | def __StripPKCS5_7Padding(self, data):
93 | paddingSize = data[-1]
94 | return data.rstrip(paddingSize.to_bytes(1, 'little'))
95 |
96 | def __paddingData(self, data):
97 | if self.paddingMode == "NoPadding":
98 | if len(data) % 16 == 0:
99 | return data
100 | else:
101 | return self.__ZeroPadding(data)
102 | elif self.paddingMode == "ZeroPadding":
103 | return self.__ZeroPadding(data)
104 | elif self.paddingMode == "PKCS5Padding" or self.paddingMode == "PKCS7Padding":
105 | return self.__PKCS5_7Padding(data)
106 | else:
107 | print("不支持Padding")
108 |
109 | def __stripPaddingData(self, data):
110 | if self.paddingMode == "NoPadding":
111 | return self.__StripZeroPadding(data)
112 | elif self.paddingMode == "ZeroPadding":
113 | return self.__StripZeroPadding(data)
114 |
115 | elif self.paddingMode == "PKCS5Padding" or self.paddingMode == "PKCS7Padding":
116 | return self.__StripPKCS5_7Padding(data)
117 | else:
118 | print("不支持Padding")
119 |
120 | def setCharacterSet(self, characterSet):
121 | '''
122 | 设置字符集编码
123 | characterSet: 字符集编码
124 | '''
125 | self.characterSet = characterSet
126 |
127 | def setPaddingMode(self, mode):
128 | '''
129 | 设置填充模式
130 | mode: 可选NoPadding,ZeroPadding,PKCS5Padding,PKCS7Padding
131 | '''
132 | self.paddingMode = mode
133 |
134 | def decryptFromBase64(self, entext):
135 | '''
136 | 从base64编码字符串编码进行AES解密
137 | entext: 数据类型str
138 | '''
139 | mData = MData(characterSet=self.characterSet)
140 | self.data = mData.fromBase64(entext)
141 | return self.__decrypt()
142 |
143 | def decryptFromHexStr(self, entext):
144 | '''
145 | 从hexstr编码字符串编码进行AES解密
146 | entext: 数据类型str
147 | '''
148 | mData = MData(characterSet=self.characterSet)
149 | self.data = mData.fromHexStr(entext)
150 | return self.__decrypt()
151 |
152 | def decryptFromString(self, entext):
153 | '''
154 | 从字符串进行AES解密
155 | entext: 数据类型str
156 | '''
157 | mData = MData(characterSet=self.characterSet)
158 | self.data = mData.fromString(entext)
159 | return self.__decrypt()
160 |
161 | def decryptFromBytes(self, entext):
162 | '''
163 | 从二进制进行AES解密
164 | entext: 数据类型bytes
165 | '''
166 | self.data = entext
167 | return self.__decrypt()
168 |
169 | def encryptFromString(self, data):
170 | '''
171 | 对字符串进行AES加密
172 | data: 待加密字符串,数据类型为str
173 | '''
174 | self.data = data.encode(self.characterSet)
175 | return self.__encrypt()
176 |
177 | def __encrypt(self):
178 | if self.mode == AES.MODE_CBC:
179 | aes = AES.new(self.key, self.mode, self.iv)
180 | elif self.mode == AES.MODE_ECB:
181 | aes = AES.new(self.key, self.mode)
182 | else:
183 | print("不支持这种模式")
184 | return
185 |
186 | data = self.__paddingData(self.data)
187 | enData = aes.encrypt(data)
188 | return MData(enData)
189 |
190 | def __decrypt(self):
191 | if self.mode == AES.MODE_CBC:
192 | aes = AES.new(self.key, self.mode, self.iv)
193 | elif self.mode == AES.MODE_ECB:
194 | aes = AES.new(self.key, self.mode)
195 | else:
196 | print("不支持这种模式")
197 | return
198 | data = aes.decrypt(self.data)
199 | mData = MData(self.__stripPaddingData(data), characterSet=self.characterSet)
200 | return mData
201 |
202 |
203 | if __name__ == '__main__':
204 | key = b"maf45J8hg022yFsi"
205 | iv = b"0000000000000000"
206 | aes = AEScryptor(key, AES.MODE_CBC, iv, paddingMode="ZeroPadding", characterSet='utf-8')
207 |
208 | data = "8888888888888888"
209 | rData = aes.encryptFromString(data)
210 | print("密文:", rData.toBase64())
211 | rData = aes.decryptFromBase64(rData.toBase64())
212 | print("明文:", rData)
213 |
--------------------------------------------------------------------------------