chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,166 @@
|
||||
## 切换到了mysql 数据库 5.7 的版本
|
||||
|
||||
```log
|
||||
$ docker logs mysqldb
|
||||
2020-12-06 23:01:40+08:00 [Note] [Entrypoint]: Entrypoint script for MySQL Server 5.7.32-1debian10 started.
|
||||
2020-12-06 23:01:41+08:00 [Note] [Entrypoint]: Switching to dedicated user 'mysql'
|
||||
2020-12-06 23:01:41+08:00 [Note] [Entrypoint]: Entrypoint script for MySQL Server 5.7.32-1debian10 started.
|
||||
2020-12-06 23:01:41+08:00 [Note] [Entrypoint]: Initializing database files
|
||||
2020-12-06T15:01:41.637316Z 0 [Warning] TIMESTAMP with implicit DEFAULT value is deprecated. Please use --explicit_defaults_for_timestamp server option (see documentation for more details).
|
||||
2020-12-06T15:01:43.872609Z 0 [Warning] InnoDB: New log files created, LSN=45790
|
||||
2020-12-06T15:01:44.535591Z 0 [Warning] InnoDB: Creating foreign key constraint system tables.
|
||||
2020-12-06T15:01:44.961598Z 0 [Warning] No existing UUID has been found, so we assume that this is the first time that this server has been started. Generating a new UUID: f4ccb5f1-37d3-11eb-8fd1-0242ac180002.
|
||||
2020-12-06T15:01:45.054324Z 0 [Warning] Gtid table is not ready to be used. Table 'mysql.gtid_executed' cannot be opened.
|
||||
2020-12-06T15:01:45.604908Z 0 [Warning] CA certificate ca.pem is self signed.
|
||||
2020-12-06T15:01:45.765331Z 1 [Warning] root@localhost is created with an empty password ! Please consider switching off the --initialize-insecure option.
|
||||
2020-12-06 23:02:35+08:00 [Note] [Entrypoint]: Database files initialized
|
||||
2020-12-06 23:02:35+08:00 [Note] [Entrypoint]: Starting temporary server
|
||||
2020-12-06 23:02:35+08:00 [Note] [Entrypoint]: Waiting for server startup
|
||||
2020-12-06T15:02:35.990607Z 0 [Warning] TIMESTAMP with implicit DEFAULT value is deprecated. Please use --explicit_defaults_for_timestamp server option (see documentation for more details).
|
||||
2020-12-06T15:02:35.992115Z 0 [Note] mysqld (mysqld 5.7.32) starting as process 81 ...
|
||||
2020-12-06T15:02:35.995048Z 0 [Note] InnoDB: PUNCH HOLE support available
|
||||
2020-12-06T15:02:35.995066Z 0 [Note] InnoDB: Mutexes and rw_locks use GCC atomic builtins
|
||||
2020-12-06T15:02:35.995070Z 0 [Note] InnoDB: Uses event mutexes
|
||||
2020-12-06T15:02:35.995075Z 0 [Note] InnoDB: GCC builtin __atomic_thread_fence() is used for memory barrier
|
||||
2020-12-06T15:02:35.995078Z 0 [Note] InnoDB: Compressed tables use zlib 1.2.11
|
||||
2020-12-06T15:02:35.995082Z 0 [Note] InnoDB: Using Linux native AIO
|
||||
2020-12-06T15:02:35.995320Z 0 [Note] InnoDB: Number of pools: 1
|
||||
2020-12-06T15:02:35.995429Z 0 [Note] InnoDB: Using CPU crc32 instructions
|
||||
2020-12-06T15:02:35.996774Z 0 [Note] InnoDB: Initializing buffer pool, total size = 128M, instances = 1, chunk size = 128M
|
||||
2020-12-06T15:02:36.007354Z 0 [Note] InnoDB: Completed initialization of buffer pool
|
||||
2020-12-06T15:02:36.009348Z 0 [Note] InnoDB: If the mysqld execution user is authorized, page cleaner thread priority can be changed. See the man page of setpriority().
|
||||
2020-12-06T15:02:36.021712Z 0 [Note] InnoDB: Highest supported file format is Barracuda.
|
||||
2020-12-06T15:02:36.153467Z 0 [Note] InnoDB: Creating shared tablespace for temporary tables
|
||||
2020-12-06T15:02:36.153634Z 0 [Note] InnoDB: Setting file './ibtmp1' size to 12 MB. Physically writing the file full; Please wait ...
|
||||
2020-12-06T15:02:37.782713Z 0 [Note] InnoDB: File './ibtmp1' size is now 12 MB.
|
||||
2020-12-06T15:02:37.784862Z 0 [Note] InnoDB: 96 redo rollback segment(s) found. 96 redo rollback segment(s) are active.
|
||||
2020-12-06T15:02:37.784894Z 0 [Note] InnoDB: 32 non-redo rollback segment(s) are active.
|
||||
2020-12-06T15:02:37.785844Z 0 [Note] InnoDB: 5.7.32 started; log sequence number 2748463
|
||||
2020-12-06T15:02:37.786241Z 0 [Note] InnoDB: Loading buffer pool(s) from /var/lib/mysql/ib_buffer_pool
|
||||
2020-12-06T15:02:37.786817Z 0 [Note] Plugin 'FEDERATED' is disabled.
|
||||
2020-12-06T15:02:37.790246Z 0 [Note] InnoDB: Buffer pool(s) load completed at 201206 23:02:37
|
||||
2020-12-06T15:02:37.803947Z 0 [Note] Found ca.pem, server-cert.pem and server-key.pem in data directory. Trying to enable SSL support using them.
|
||||
2020-12-06T15:02:37.803988Z 0 [Note] Skipping generation of SSL certificates as certificate files are present in data directory.
|
||||
2020-12-06T15:02:37.806098Z 0 [Warning] CA certificate ca.pem is self signed.
|
||||
2020-12-06T15:02:37.806183Z 0 [Note] Skipping generation of RSA key pair as key files are present in data directory.
|
||||
2020-12-06T15:02:37.950541Z 0 [Warning] Insecure configuration for --pid-file: Location '/var/run/mysqld' in the path is accessible to all OS users. Consider choosing a different directory.
|
||||
2020-12-06T15:02:37.973492Z 0 [Note] Event Scheduler: Loaded 0 events
|
||||
2020-12-06T15:02:37.974048Z 0 [Note] mysqld: ready for connections.
|
||||
Version: '5.7.32' socket: '/var/run/mysqld/mysqld.sock' port: 0 MySQL Community Server (GPL)
|
||||
2020-12-06 23:02:38+08:00 [Note] [Entrypoint]: Temporary server started.
|
||||
Warning: Unable to load '/usr/share/zoneinfo/iso3166.tab' as time zone. Skipping it.
|
||||
Warning: Unable to load '/usr/share/zoneinfo/leap-seconds.list' as time zone. Skipping it.
|
||||
Warning: Unable to load '/usr/share/zoneinfo/zone.tab' as time zone. Skipping it.
|
||||
Warning: Unable to load '/usr/share/zoneinfo/zone1970.tab' as time zone. Skipping it.
|
||||
2020-12-06 23:02:54+08:00 [Note] [Entrypoint]: Creating database stock_data
|
||||
|
||||
2020-12-06 23:02:54+08:00 [Note] [Entrypoint]: Stopping temporary server
|
||||
2020-12-06T15:02:54.825959Z 0 [Note] Giving 0 client threads a chance to die gracefully
|
||||
2020-12-06T15:02:54.825987Z 0 [Note] Shutting down slave threads
|
||||
2020-12-06T15:02:54.825992Z 0 [Note] Forcefully disconnecting 0 remaining clients
|
||||
2020-12-06T15:02:54.825998Z 0 [Note] Event Scheduler: Purging the queue. 0 events
|
||||
2020-12-06T15:02:54.826139Z 0 [Note] Binlog end
|
||||
2020-12-06T15:02:54.826658Z 0 [Note] Shutting down plugin 'ngram'
|
||||
2020-12-06T15:02:54.826669Z 0 [Note] Shutting down plugin 'partition'
|
||||
2020-12-06T15:02:54.826673Z 0 [Note] Shutting down plugin 'BLACKHOLE'
|
||||
2020-12-06T15:02:54.826677Z 0 [Note] Shutting down plugin 'ARCHIVE'
|
||||
2020-12-06T15:02:54.826682Z 0 [Note] Shutting down plugin 'PERFORMANCE_SCHEMA'
|
||||
2020-12-06T15:02:54.826714Z 0 [Note] Shutting down plugin 'MRG_MYISAM'
|
||||
2020-12-06T15:02:54.826723Z 0 [Note] Shutting down plugin 'MyISAM'
|
||||
2020-12-06T15:02:54.826732Z 0 [Note] Shutting down plugin 'INNODB_SYS_VIRTUAL'
|
||||
2020-12-06T15:02:54.826737Z 0 [Note] Shutting down plugin 'INNODB_SYS_DATAFILES'
|
||||
2020-12-06T15:02:54.826741Z 0 [Note] Shutting down plugin 'INNODB_SYS_TABLESPACES'
|
||||
2020-12-06T15:02:54.826746Z 0 [Note] Shutting down plugin 'INNODB_SYS_FOREIGN_COLS'
|
||||
2020-12-06T15:02:54.826749Z 0 [Note] Shutting down plugin 'INNODB_SYS_FOREIGN'
|
||||
2020-12-06T15:02:54.826786Z 0 [Note] Shutting down plugin 'INNODB_SYS_FIELDS'
|
||||
2020-12-06T15:02:54.826791Z 0 [Note] Shutting down plugin 'INNODB_SYS_COLUMNS'
|
||||
2020-12-06T15:02:54.826795Z 0 [Note] Shutting down plugin 'INNODB_SYS_INDEXES'
|
||||
2020-12-06T15:02:54.826800Z 0 [Note] Shutting down plugin 'INNODB_SYS_TABLESTATS'
|
||||
2020-12-06T15:02:54.826804Z 0 [Note] Shutting down plugin 'INNODB_SYS_TABLES'
|
||||
2020-12-06T15:02:54.826808Z 0 [Note] Shutting down plugin 'INNODB_FT_INDEX_TABLE'
|
||||
2020-12-06T15:02:54.826811Z 0 [Note] Shutting down plugin 'INNODB_FT_INDEX_CACHE'
|
||||
2020-12-06T15:02:54.826813Z 0 [Note] Shutting down plugin 'INNODB_FT_CONFIG'
|
||||
2020-12-06T15:02:54.826816Z 0 [Note] Shutting down plugin 'INNODB_FT_BEING_DELETED'
|
||||
2020-12-06T15:02:54.826819Z 0 [Note] Shutting down plugin 'INNODB_FT_DELETED'
|
||||
2020-12-06T15:02:54.826822Z 0 [Note] Shutting down plugin 'INNODB_FT_DEFAULT_STOPWORD'
|
||||
2020-12-06T15:02:54.826825Z 0 [Note] Shutting down plugin 'INNODB_METRICS'
|
||||
2020-12-06T15:02:54.826828Z 0 [Note] Shutting down plugin 'INNODB_TEMP_TABLE_INFO'
|
||||
2020-12-06T15:02:54.826831Z 0 [Note] Shutting down plugin 'INNODB_BUFFER_POOL_STATS'
|
||||
2020-12-06T15:02:54.826834Z 0 [Note] Shutting down plugin 'INNODB_BUFFER_PAGE_LRU'
|
||||
2020-12-06T15:02:54.826836Z 0 [Note] Shutting down plugin 'INNODB_BUFFER_PAGE'
|
||||
2020-12-06T15:02:54.826839Z 0 [Note] Shutting down plugin 'INNODB_CMP_PER_INDEX_RESET'
|
||||
2020-12-06T15:02:54.826842Z 0 [Note] Shutting down plugin 'INNODB_CMP_PER_INDEX'
|
||||
2020-12-06T15:02:54.826845Z 0 [Note] Shutting down plugin 'INNODB_CMPMEM_RESET'
|
||||
2020-12-06T15:02:54.826848Z 0 [Note] Shutting down plugin 'INNODB_CMPMEM'
|
||||
2020-12-06T15:02:54.826851Z 0 [Note] Shutting down plugin 'INNODB_CMP_RESET'
|
||||
2020-12-06T15:02:54.826854Z 0 [Note] Shutting down plugin 'INNODB_CMP'
|
||||
2020-12-06T15:02:54.826857Z 0 [Note] Shutting down plugin 'INNODB_LOCK_WAITS'
|
||||
2020-12-06T15:02:54.826859Z 0 [Note] Shutting down plugin 'INNODB_LOCKS'
|
||||
2020-12-06T15:02:54.826862Z 0 [Note] Shutting down plugin 'INNODB_TRX'
|
||||
2020-12-06T15:02:54.826910Z 0 [Note] Shutting down plugin 'InnoDB'
|
||||
2020-12-06T15:02:54.826953Z 0 [Note] InnoDB: FTS optimize thread exiting.
|
||||
2020-12-06T15:02:54.827046Z 0 [Note] InnoDB: Starting shutdown...
|
||||
2020-12-06T15:02:54.927339Z 0 [Note] InnoDB: Dumping buffer pool(s) to /var/lib/mysql/ib_buffer_pool
|
||||
2020-12-06T15:02:54.993267Z 0 [Note] InnoDB: Buffer pool(s) dump completed at 201206 23:02:54
|
||||
2020-12-06T15:02:57.668186Z 0 [Note] InnoDB: Shutdown completed; log sequence number 12619636
|
||||
2020-12-06T15:02:57.673193Z 0 [Note] InnoDB: Removed temporary tablespace data file: "ibtmp1"
|
||||
2020-12-06T15:02:57.673260Z 0 [Note] Shutting down plugin 'MEMORY'
|
||||
2020-12-06T15:02:57.673278Z 0 [Note] Shutting down plugin 'CSV'
|
||||
2020-12-06T15:02:57.673291Z 0 [Note] Shutting down plugin 'sha256_password'
|
||||
2020-12-06T15:02:57.673302Z 0 [Note] Shutting down plugin 'mysql_native_password'
|
||||
2020-12-06T15:02:57.673866Z 0 [Note] Shutting down plugin 'binlog'
|
||||
2020-12-06T15:02:57.677294Z 0 [Note] mysqld: Shutdown complete
|
||||
|
||||
2020-12-06 23:02:57+08:00 [Note] [Entrypoint]: Temporary server stopped
|
||||
|
||||
2020-12-06 23:02:57+08:00 [Note] [Entrypoint]: MySQL init process done. Ready for start up.
|
||||
|
||||
2020-12-06T15:02:58.038797Z 0 [Warning] TIMESTAMP with implicit DEFAULT value is deprecated. Please use --explicit_defaults_for_timestamp server option (see documentation for more details).
|
||||
2020-12-06T15:02:58.040198Z 0 [Note] mysqld (mysqld 5.7.32) starting as process 1 ...
|
||||
2020-12-06T15:02:58.043137Z 0 [Note] InnoDB: PUNCH HOLE support available
|
||||
2020-12-06T15:02:58.043152Z 0 [Note] InnoDB: Mutexes and rw_locks use GCC atomic builtins
|
||||
2020-12-06T15:02:58.043155Z 0 [Note] InnoDB: Uses event mutexes
|
||||
2020-12-06T15:02:58.043158Z 0 [Note] InnoDB: GCC builtin __atomic_thread_fence() is used for memory barrier
|
||||
2020-12-06T15:02:58.043161Z 0 [Note] InnoDB: Compressed tables use zlib 1.2.11
|
||||
2020-12-06T15:02:58.043163Z 0 [Note] InnoDB: Using Linux native AIO
|
||||
2020-12-06T15:02:58.043392Z 0 [Note] InnoDB: Number of pools: 1
|
||||
2020-12-06T15:02:58.043486Z 0 [Note] InnoDB: Using CPU crc32 instructions
|
||||
2020-12-06T15:02:58.044796Z 0 [Note] InnoDB: Initializing buffer pool, total size = 128M, instances = 1, chunk size = 128M
|
||||
2020-12-06T15:02:58.055082Z 0 [Note] InnoDB: Completed initialization of buffer pool
|
||||
2020-12-06T15:02:58.057154Z 0 [Note] InnoDB: If the mysqld execution user is authorized, page cleaner thread priority can be changed. See the man page of setpriority().
|
||||
2020-12-06T15:02:58.068627Z 0 [Note] InnoDB: Highest supported file format is Barracuda.
|
||||
2020-12-06T15:02:58.191412Z 0 [Note] InnoDB: Creating shared tablespace for temporary tables
|
||||
2020-12-06T15:02:58.191760Z 0 [Note] InnoDB: Setting file './ibtmp1' size to 12 MB. Physically writing the file full; Please wait ...
|
||||
2020-12-06T15:02:58.636078Z 0 [Note] InnoDB: File './ibtmp1' size is now 12 MB.
|
||||
2020-12-06T15:02:58.638452Z 0 [Note] InnoDB: 96 redo rollback segment(s) found. 96 redo rollback segment(s) are active.
|
||||
2020-12-06T15:02:58.638497Z 0 [Note] InnoDB: 32 non-redo rollback segment(s) are active.
|
||||
2020-12-06T15:02:58.639548Z 0 [Note] InnoDB: Waiting for purge to start
|
||||
2020-12-06T15:02:58.689910Z 0 [Note] InnoDB: 5.7.32 started; log sequence number 12619636
|
||||
2020-12-06T15:02:58.690442Z 0 [Note] InnoDB: Loading buffer pool(s) from /var/lib/mysql/ib_buffer_pool
|
||||
2020-12-06T15:02:58.691219Z 0 [Note] Plugin 'FEDERATED' is disabled.
|
||||
2020-12-06T15:02:58.702492Z 0 [Note] InnoDB: Buffer pool(s) load completed at 201206 23:02:58
|
||||
2020-12-06T15:02:58.715442Z 0 [Note] Found ca.pem, server-cert.pem and server-key.pem in data directory. Trying to enable SSL support using them.
|
||||
2020-12-06T15:02:58.715904Z 0 [Note] Skipping generation of SSL certificates as certificate files are present in data directory.
|
||||
2020-12-06T15:02:58.717982Z 0 [Warning] CA certificate ca.pem is self signed.
|
||||
2020-12-06T15:02:58.718051Z 0 [Note] Skipping generation of RSA key pair as key files are present in data directory.
|
||||
2020-12-06T15:02:58.719045Z 0 [Note] Server hostname (bind-address): '*'; port: 3306
|
||||
2020-12-06T15:02:58.720034Z 0 [Note] IPv6 is available.
|
||||
2020-12-06T15:02:58.720077Z 0 [Note] - '::' resolves to '::';
|
||||
2020-12-06T15:02:58.720116Z 0 [Note] Server socket created on IP: '::'.
|
||||
2020-12-06T15:02:59.182050Z 0 [Warning] Insecure configuration for --pid-file: Location '/var/run/mysqld' in the path is accessible to all OS users. Consider choosing a different directory.
|
||||
2020-12-06T15:02:59.217680Z 0 [Note] Event Scheduler: Loaded 0 events
|
||||
2020-12-06T15:02:59.218060Z 0 [Note] mysqld: ready for connections.
|
||||
Version: '5.7.32' socket: '/var/run/mysqld/mysqld.sock' port: 3306 MySQL Community Server (GPL)
|
||||
|
||||
```
|
||||
|
||||
要是第一次启动,没有数据,启动会比较慢,需要1分多钟,为了保险,定2分钟后执行初始化任务。
|
||||
|
||||
|
||||
## 2,初始化数据接口被停用
|
||||
|
||||
```
|
||||
本接口即将停止更新,请尽快使用Pro版接口:https://tushare.pro/document/2
|
||||
error : HTTP Error 404: Not Found
|
||||
|
||||
```
|
||||
@@ -0,0 +1,7 @@
|
||||
|
||||
## 创建 tag 并发布到 github 上
|
||||
|
||||
|
||||
git tag -a v2.0 -m "v2.0"
|
||||
|
||||
git push origin --tags
|
||||
@@ -0,0 +1,182 @@
|
||||
#!/usr/local/bin/python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
|
||||
import libs.common as common
|
||||
import sys
|
||||
import time
|
||||
import pandas as pd
|
||||
import numpy as np
|
||||
from sqlalchemy.types import NVARCHAR
|
||||
from sqlalchemy import inspect
|
||||
import datetime
|
||||
import akshare as ak
|
||||
import traceback
|
||||
import MySQLdb
|
||||
|
||||
# 600开头的股票是上证A股,属于大盘股
|
||||
# 600开头的股票是上证A股,属于大盘股,其中6006开头的股票是最早上市的股票,
|
||||
# 6016开头的股票为大盘蓝筹股;900开头的股票是上证B股;
|
||||
# 000开头的股票是深证A股,001、002开头的股票也都属于深证A股,
|
||||
# 其中002开头的股票是深证A股中小企业股票;
|
||||
# 200开头的股票是深证B股;
|
||||
# 300开头的股票是创业板股票;400开头的股票是三板市场股票。
|
||||
def stock_a(code):
|
||||
# print(code)
|
||||
# print(type(code))
|
||||
# 上证A股 # 深证A股
|
||||
if code.startswith('600') or code.startswith('6006') or code.startswith('601') or code.startswith('000') or code.startswith('001') or code.startswith('002'):
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
# 过滤掉 st 股票。
|
||||
def stock_a_filter_st(name):
|
||||
# print(code)
|
||||
# print(type(code))
|
||||
# 上证A股 # 深证A股
|
||||
if name.find("ST") == -1:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
# 过滤价格,如果没有基本上是退市了。
|
||||
def stock_a_filter_price(latest_price):
|
||||
# float 在 pandas 里面判断 空。
|
||||
if np.isnan(latest_price):
|
||||
return False
|
||||
else:
|
||||
return True
|
||||
|
||||
####### 3.pdf 方法。宏观经济数据
|
||||
# 接口全部有错误。只专注股票数据。
|
||||
def stat_all(tmp_datetime):
|
||||
|
||||
datetime_str = (tmp_datetime).strftime("%Y-%m-%d")
|
||||
datetime_int = (tmp_datetime).strftime("%Y%m%d")
|
||||
print("datetime_str:", datetime_str)
|
||||
print("datetime_int:", datetime_int)
|
||||
|
||||
# 股票列表
|
||||
try:
|
||||
data = ak.stock_zh_a_spot_em()
|
||||
# print(data.index)
|
||||
# 解决ESP 小数问题。
|
||||
# data["esp"] = data["esp"].round(2) # 数据保留2位小数
|
||||
data.columns = ['index', 'code', 'name', 'last_price', 'change_percent', 'change_amount',
|
||||
'volume', 'turnover', 'amplitude', 'high', 'low', 'open', 'closed', 'volume_ratio',
|
||||
'turnover_rate', 'pe_ratio','pb_ratio', 'market_cap','circulating_market_cap','rise_speed',
|
||||
'change_5min', 'change_ercent_60day','ytd_change_percent']
|
||||
|
||||
data = data.loc[data["code"].apply(stock_a)].loc[data["name"].apply(stock_a_filter_st)].loc[
|
||||
data["last_price"].apply(stock_a_filter_price)]
|
||||
print(data)
|
||||
data['date'] = datetime_int # 修改时间成为int类型。
|
||||
|
||||
# 删除老数据。
|
||||
del_sql = " DELETE FROM `stock_zh_a_spot_em` where `date` = '%s' " % datetime_int
|
||||
common.insert(del_sql)
|
||||
|
||||
data.set_index('code', inplace=True)
|
||||
data.drop('index', axis=1, inplace=True)
|
||||
print(data)
|
||||
# 删除index,然后和原始数据合并。
|
||||
common.insert_db(data, "stock_zh_a_spot_em", True, "`date`,`code`")
|
||||
except Exception as e:
|
||||
print("error :", e)
|
||||
traceback.print_exc()
|
||||
|
||||
|
||||
|
||||
# 龙虎榜-个股上榜统计
|
||||
# 接口: stock_lhb_ggtj_sina
|
||||
#
|
||||
# 目标地址: http://vip.stock.finance.sina.com.cn/q/go.php/vLHBData/kind/ggtj/index.phtml
|
||||
#
|
||||
# 描述: 获取新浪财经-龙虎榜-个股上榜统计
|
||||
#
|
||||
|
||||
try:
|
||||
stock_lhb_ggtj_sina = ak.stock_lhb_ggtj_sina(symbol="5")
|
||||
print(stock_lhb_ggtj_sina)
|
||||
|
||||
stock_lhb_ggtj_sina.columns = ['code', 'name', 'ranking_times', 'sum_buy', 'sum_sell', 'net_amount', 'buy_seat',
|
||||
'sell_seat']
|
||||
|
||||
stock_lhb_ggtj_sina = stock_lhb_ggtj_sina.loc[stock_lhb_ggtj_sina["code"].apply(stock_a)].loc[
|
||||
stock_lhb_ggtj_sina["name"].apply(stock_a_filter_st)]
|
||||
|
||||
stock_lhb_ggtj_sina.set_index('code', inplace=True)
|
||||
# data_sina_lhb.drop('index', axis=1, inplace=True)
|
||||
# 删除老数据。
|
||||
stock_lhb_ggtj_sina['date'] = datetime_int # 修改时间成为int类型。
|
||||
|
||||
# 删除老数据。
|
||||
del_sql = " DELETE FROM `stock_lhb_ggtj_sina` where `date` = '%s' " % datetime_int
|
||||
common.insert(del_sql)
|
||||
|
||||
common.insert_db(stock_lhb_ggtj_sina, "stock_lhb_ggtj_sina", True, "`date`,`code`")
|
||||
|
||||
except Exception as e:
|
||||
print("error :", e)
|
||||
traceback.print_exc()
|
||||
|
||||
|
||||
|
||||
# 每日统计
|
||||
# 接口: stock_dzjy_mrtj
|
||||
#
|
||||
# 目标地址: http://data.eastmoney.com/dzjy/dzjy_mrtj.aspx
|
||||
#
|
||||
# 描述: 获取东方财富网-数据中心-大宗交易-每日统计
|
||||
# https://akshare.akfamily.xyz/data/stock/stock.html#id318
|
||||
# import akshare as ak
|
||||
# stock_dzjy_mrtj_df = ak.stock_dzjy_mrtj(start_date='20220105', end_date='20220105')
|
||||
# print(stock_dzjy_mrtj_df)
|
||||
|
||||
try:
|
||||
|
||||
print("################ tmp_datetime : " + datetime_int)
|
||||
# 格式要 int类型日期
|
||||
stock_dzjy_mrtj = ak.stock_dzjy_mrtj(start_date=datetime_int, end_date=datetime_int)
|
||||
print(stock_dzjy_mrtj)
|
||||
|
||||
stock_dzjy_mrtj.columns = ['index', 'trade_date', 'code', 'name', 'quote_change', 'close_price', 'average_price',
|
||||
'overflow_rate', 'trade_number', 'sum_volume', 'sum_turnover',
|
||||
'turnover_market_rate']
|
||||
|
||||
stock_dzjy_mrtj.set_index('code', inplace=True)
|
||||
# data_sina_lhb.drop('index', axis=1, inplace=True)
|
||||
# 删除老数据。
|
||||
stock_dzjy_mrtj['date'] = datetime_int # 修改时间成为int类型。
|
||||
stock_dzjy_mrtj.drop('trade_date', axis=1, inplace=True)
|
||||
stock_dzjy_mrtj.drop('index', axis=1, inplace=True)
|
||||
|
||||
# 数据保留2位小数
|
||||
try:
|
||||
stock_dzjy_mrtj = stock_dzjy_mrtj.loc[stock_dzjy_mrtj["code"].apply(stock_a)].loc[
|
||||
stock_dzjy_mrtj["name"].apply(stock_a_filter_st)]
|
||||
|
||||
stock_dzjy_mrtj["average_price"] = stock_dzjy_mrtj["average_price"].round(2)
|
||||
stock_dzjy_mrtj["overflow_rate"] = stock_dzjy_mrtj["overflow_rate"].round(4)
|
||||
stock_dzjy_mrtj["turnover_market_rate"] = stock_dzjy_mrtj["turnover_market_rate"].round(6)
|
||||
except Exception as e:
|
||||
print("round error :", e)
|
||||
traceback.print_exc()
|
||||
|
||||
# 删除老数据。
|
||||
del_sql = " DELETE FROM `stock_dzjy_mrtj` where `date` = '%s' " % datetime_int
|
||||
common.insert(del_sql)
|
||||
|
||||
print(stock_dzjy_mrtj)
|
||||
|
||||
common.insert_db(stock_dzjy_mrtj, "stock_dzjy_mrtj", True, "`date`,`code`")
|
||||
|
||||
except Exception as e:
|
||||
print("error :", e)
|
||||
traceback.print_exc()
|
||||
|
||||
# main函数入口
|
||||
if __name__ == '__main__':
|
||||
# 执行数据初始化。
|
||||
# 使用方法传递。
|
||||
tmp_datetime = common.run_with_args(stat_all)
|
||||
@@ -0,0 +1,4 @@
|
||||
1,计算每日买全部推荐买。
|
||||
2,计算每日全部推荐卖数据。
|
||||
3,设置个人账号,设置购买和卖的数据。进行关联查询。
|
||||
4,最重要的沪深300,中正500数据。进行大盘股分析。
|
||||
@@ -0,0 +1,24 @@
|
||||
#!/usr/local/bin/python3
|
||||
# -*- coding: utf-8 -*-
|
||||
from pytz import utc
|
||||
from apscheduler.jobstores.sqlalchemy import SQLAlchemyJobStore
|
||||
from apscheduler.schedulers.blocking import BlockingScheduler
|
||||
|
||||
from apscheduler.executors.pool import ProcessPoolExecutor
|
||||
import libs.common as common
|
||||
|
||||
# doc : http://apscheduler.readthedocs.io/en/latest/modules/jobstores/sqlalchemy.html
|
||||
jobstores = {
|
||||
'default': SQLAlchemyJobStore(url=common.MYSQL_CONN_URL, tablename='apscheduler_jobs')
|
||||
}
|
||||
executors = {
|
||||
'default': {'type': 'threadpool', 'max_workers': 20},
|
||||
'processpool': ProcessPoolExecutor(max_workers=5)
|
||||
}
|
||||
job_defaults = {
|
||||
'coalesce': False,
|
||||
'max_instances': 3
|
||||
}
|
||||
scheduler = BlockingScheduler(jobstores=jobstores, executors=executors, job_defaults=job_defaults, timezone=utc)
|
||||
scheduler.start()
|
||||
print("start ...")
|
||||
@@ -0,0 +1,33 @@
|
||||
#!/usr/local/bin/python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import libs.common as common
|
||||
import MySQLdb
|
||||
|
||||
# 创建新数据库。
|
||||
def create_new_database():
|
||||
with MySQLdb.connect(common.MYSQL_HOST, common.MYSQL_USER, common.MYSQL_PWD, "mysql", charset="utf8") as db:
|
||||
try:
|
||||
create_sql = " CREATE DATABASE IF NOT EXISTS %s CHARACTER SET utf8 COLLATE utf8_general_ci " % common.MYSQL_DB
|
||||
print(create_sql)
|
||||
db.autocommit(on=True)
|
||||
db.cursor().execute(create_sql)
|
||||
except Exception as e:
|
||||
print("error CREATE DATABASE :", e)
|
||||
|
||||
|
||||
# main函数入口
|
||||
if __name__ == '__main__':
|
||||
|
||||
# 检查,如果执行 select 1 失败,说明数据库不存在,然后创建一个新的数据库。
|
||||
try:
|
||||
with MySQLdb.connect(common.MYSQL_HOST, common.MYSQL_USER, common.MYSQL_PWD, common.MYSQL_DB,
|
||||
charset="utf8") as db:
|
||||
db.autocommit(on=True)
|
||||
db.cursor().execute(" select 1 ")
|
||||
print("########### db exists ###########")
|
||||
except Exception as e:
|
||||
print("check MYSQL_DB error and create new one :", e)
|
||||
# 检查数据库失败,
|
||||
create_new_database()
|
||||
# 执行数据初始化。
|
||||
Executable
+28
@@ -0,0 +1,28 @@
|
||||
#!/bin/sh
|
||||
|
||||
mkdir -p /data/logs
|
||||
DATETIME=`date +%Y-%m-%d:%H:%M:%S`
|
||||
|
||||
DATE=`date +%Y-%m-%d`
|
||||
|
||||
export PYTHONIOENCODING=utf-8
|
||||
export LANG=zh_CN.UTF-8
|
||||
export PYTHONPATH=/data/stock
|
||||
export LC_CTYPE=zh_CN.UTF-8
|
||||
|
||||
|
||||
echo "###################"$DATETIME"###################" >> /data/logs/daily.${DATE}.log
|
||||
#增加获得今日全部数据和大盘数据
|
||||
/usr/local/bin/python3 /data/stock/jobs/18h_daily_job.py >> /data/logs/daily.${DATE}.log
|
||||
|
||||
|
||||
echo "###################"$DATETIME"###################" >> /data/logs/daily.${DATE}.log
|
||||
#使用股票指标预测。
|
||||
/usr/local/bin/python3 /data/stock/jobs/guess_indicators_daily_job.py >> /data/logs/daily.${DATE}.log
|
||||
/usr/local/bin/python3 /data/stock/jobs/guess_indicators_daily_buy_job.py >> /data/logs/daily.${DATE}.log
|
||||
|
||||
#清除前3天数据。
|
||||
DATE_20=`date -d '-20 days' +%Y-%m-%d`
|
||||
MONTH_20=`date -d '-20 days' +%Y-%m`
|
||||
echo "rm -f /data/cache/hist_data_cache/${MONTH_20}/${DATETIME_20}"
|
||||
rm -f /data/cache/hist_data_cache/${MONTH_20}/${DATETIME_20}
|
||||
Executable
+6
@@ -0,0 +1,6 @@
|
||||
#!/bin/sh
|
||||
|
||||
mkdir -p /data/logs
|
||||
DATE=`date +%Y-%m-%d:%H:%M:%S`
|
||||
echo $DATE >> /data/logs/hourly.log
|
||||
|
||||
Executable
+5
@@ -0,0 +1,5 @@
|
||||
#!/bin/bash
|
||||
|
||||
mkdir -p /data/logs
|
||||
DATE=`date +%Y-%m-%d:%H:%M:%S`
|
||||
echo $DATE >> /data/logs/1min.log
|
||||
Executable
+6
@@ -0,0 +1,6 @@
|
||||
#!/bin/sh
|
||||
|
||||
mkdir -p /data/logs
|
||||
DATE=`date +%Y-%m-%d:%H:%M:%S`
|
||||
echo $DATE >> /data/logs/monthly.log
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
SHELL=/bin/sh
|
||||
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
|
||||
*/1 * * * * /bin/run-parts /etc/cron.minutely
|
||||
10 * * * * /bin/run-parts /etc/cron.hourly
|
||||
30 16 * * * /bin/run-parts /etc/cron.daily
|
||||
30 17 1,10,20 * * /bin/run-parts /etc/cron.monthly
|
||||
@@ -0,0 +1,49 @@
|
||||
#!/usr/local/bin/python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
|
||||
import libs.common as common
|
||||
import sys
|
||||
import os
|
||||
import time
|
||||
import pandas as pd
|
||||
import tushare as ts
|
||||
from sqlalchemy.types import NVARCHAR
|
||||
from sqlalchemy import inspect
|
||||
import datetime
|
||||
import shutil
|
||||
|
||||
|
||||
####### 使用 5.pdf,先做 基本面数据 的数据,然后在做交易数据。
|
||||
#
|
||||
def stat_all(tmp_datetime):
|
||||
datetime_str = (tmp_datetime).strftime("%Y-%m-%d")
|
||||
datetime_int = (tmp_datetime).strftime("%Y%m%d")
|
||||
|
||||
cache_dir = common.bash_stock_tmp % (datetime_str[0:7], datetime_str)
|
||||
if os.path.exists(cache_dir):
|
||||
shutil.rmtree(cache_dir)
|
||||
print("remove cache dir force :", cache_dir)
|
||||
|
||||
print("datetime_str:", datetime_str)
|
||||
print("datetime_int:", datetime_int)
|
||||
data = ts.top_list(datetime_str)
|
||||
# 处理重复数据,保存最新一条数据。最后一步处理,否则concat有问题。
|
||||
#
|
||||
if not data is None and len(data) > 0:
|
||||
# 插入数据库。
|
||||
# del data["reason"]
|
||||
data["date"] = datetime_int # 修改时间成为int类型。
|
||||
data = data.drop_duplicates(subset="code", keep="last")
|
||||
data.head(n=1)
|
||||
common.insert_db(data, "ts_top_list", False, "`date`,`code`")
|
||||
else:
|
||||
print("no data .")
|
||||
|
||||
print(datetime_str)
|
||||
|
||||
|
||||
# main函数入口
|
||||
if __name__ == '__main__':
|
||||
# 使用方法传递。
|
||||
tmp_datetime = common.run_with_args(stat_all)
|
||||
@@ -0,0 +1,77 @@
|
||||
#!/usr/local/bin/python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
|
||||
import libs.common as common
|
||||
import pandas as pd
|
||||
import numpy as np
|
||||
import math
|
||||
import datetime
|
||||
import stockstats
|
||||
from sqlalchemy import text
|
||||
|
||||
|
||||
### 对每日指标数据,进行筛选。将符合条件的。二次筛选出来。
|
||||
### 只是做简单筛选
|
||||
def stat_all_lite_buy(tmp_datetime):
|
||||
datetime_str = (tmp_datetime).strftime("%Y-%m-%d")
|
||||
datetime_int = (tmp_datetime).strftime("%Y%m%d")
|
||||
print("datetime_str:", datetime_str)
|
||||
print("datetime_int:", datetime_int)
|
||||
|
||||
# 查询参数
|
||||
params = {"datetime": datetime_int}
|
||||
|
||||
sql_kdjk = text(" SELECT avg(`kdjk`) as avg_kdjk FROM guess_indicators_daily ")
|
||||
data_kdjk = pd.read_sql(sql=sql_kdjk, con=common.engine(), params=params)
|
||||
kdjk = data_kdjk["avg_kdjk"][0]
|
||||
|
||||
sql_kdjd = text(" SELECT avg(`kdjd`) as avg_kdjd FROM guess_indicators_daily ")
|
||||
data_kdjd = pd.read_sql(sql=sql_kdjd, con=common.engine(), params=params)
|
||||
kdjd = data_kdjd["avg_kdjd"][0]
|
||||
|
||||
sql_kdjj = text(" SELECT avg(`kdjj`) as avg_kdjj FROM guess_indicators_daily ")
|
||||
data_kdjj = pd.read_sql(sql=sql_kdjj, con=common.engine(), params=params)
|
||||
kdjj = data_kdjj["avg_kdjj"][0]
|
||||
|
||||
# K值在80以上,D值在70以上,J值大于90时为超买。
|
||||
# J大于100时为超买,小于10时为超卖。
|
||||
# 当六日指标上升到达80时,表示股市已有超买现象
|
||||
# 当CCI>﹢100 时,表明股价已经进入非常态区间——超买区间,股价的异动现象应多加关注。
|
||||
params_1 = {"datetime": datetime_int, "kdjk": kdjk, "kdjd": kdjd, "kdjj": kdjj}
|
||||
sql_1 = text("""
|
||||
SELECT `date`,`code`,`name`,`last_price`,`change_percent`,`change_amount`,`volume`,`turnover`,
|
||||
`amplitude`,`high`,`low`,`open`,`closed`,`volume_ratio`,`turnover_rate`,
|
||||
`pe_ratio`,`pb_ratio`,`market_cap`,`circulating_market_cap`,`rise_speed`,
|
||||
`change_5min`,`change_ercent_60day`,`ytd_change_percent`,
|
||||
`boll`, `boll_lb`, `boll_ub`, `kdjd`, `kdjj`, `kdjk`, `macd`, `macdh`,
|
||||
`macds`, `pdi`,`trix`, `trix_9_sma`, `vr`, `vr_6_sma`, `wr_10`, `wr_6`
|
||||
FROM stock_data.guess_indicators_daily WHERE `date` = :datetime
|
||||
and kdjk >= :kdjk and kdjd >= :kdjd and kdjj >= :kdjj
|
||||
""") # and kdjj > 100 and rsi_6 > 80 and cci > 100 # 调整参数,提前获得股票增长。
|
||||
|
||||
try:
|
||||
# 删除老数据。
|
||||
del_sql = " DELETE FROM `stock_data`.`guess_indicators_lite_buy_daily` WHERE `date`= '%s' " % datetime_int
|
||||
common.insert(del_sql)
|
||||
except Exception as e:
|
||||
print("error :", e)
|
||||
|
||||
print(f"sql_1 : {sql_1}")
|
||||
data = pd.read_sql(sql=sql_1, con=common.engine(), params=params_1)
|
||||
data = data.drop_duplicates(subset="code", keep="last")
|
||||
print("######## stat_all_lite_buy len data ########:", len(data))
|
||||
|
||||
try:
|
||||
common.insert_db(data, "guess_indicators_lite_buy_daily", False, "`date`,`code`")
|
||||
except Exception as e:
|
||||
print("error :", e)
|
||||
|
||||
|
||||
|
||||
# main函数入口
|
||||
if __name__ == '__main__':
|
||||
# 使用方法传递。
|
||||
# 二次筛选数据。直接计算买卖股票数据。
|
||||
tmp_datetime = common.run_with_args(stat_all_lite_buy)
|
||||
|
||||
@@ -0,0 +1,278 @@
|
||||
#!/usr/local/bin/python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
|
||||
import libs.common as common
|
||||
import pandas as pd
|
||||
import numpy as np
|
||||
import math
|
||||
import datetime
|
||||
import stockstats
|
||||
|
||||
# 批处理数据。
|
||||
def stat_all_batch(tmp_datetime):
|
||||
datetime_str = (tmp_datetime).strftime("%Y-%m-%d")
|
||||
datetime_int = (tmp_datetime).strftime("%Y%m%d")
|
||||
print("datetime_str:", datetime_str)
|
||||
print("datetime_int:", datetime_int)
|
||||
|
||||
try:
|
||||
# 删除老数据。
|
||||
del_sql = " DELETE FROM `guess_indicators_daily` WHERE `date`= %s " % datetime_int
|
||||
common.insert(del_sql)
|
||||
except Exception as e:
|
||||
print("error :", e)
|
||||
|
||||
sql_count = """
|
||||
SELECT count(1) FROM stock_zh_a_spot_em WHERE `date` = %s and `open` > 0
|
||||
"""
|
||||
# 修改逻辑,增加中小板块计算。 中小板:002,创业板:300 。已经是经过筛选的数据了。
|
||||
count = common.select_count(sql_count, params=[datetime_int])
|
||||
print("count :", count)
|
||||
batch_size = 100
|
||||
end = int(math.ceil(float(count) / batch_size) * batch_size)
|
||||
print(end)
|
||||
for i in range(0, end, batch_size):
|
||||
print("loop :", i)
|
||||
# 查询今日满足股票数据。剔除数据:创业板股票数据,中小板股票数据,所有st股票
|
||||
# #`code` not like '002%' and `code` not like '300%' and `name` not like '%st%'
|
||||
sql_1 = """
|
||||
SELECT `date`,`code`,`name`,`last_price`,`change_percent`,`change_amount`,`volume`,`turnover`,
|
||||
`amplitude`,`high`,`low`,`open`,`closed`,`volume_ratio`,`turnover_rate`,
|
||||
`pe_ratio`,`pb_ratio`,`market_cap`,`circulating_market_cap`,`rise_speed`,
|
||||
`change_5min`,`change_ercent_60day`,`ytd_change_percent`
|
||||
FROM stock_zh_a_spot_em WHERE `date` = %s and `open` > 0 limit %s , %s
|
||||
"""
|
||||
sql_2 = sql_1 % (datetime_int, i, batch_size)
|
||||
print(sql_2)
|
||||
# data = pd.read_sql(sql=sql_1, con=common.engine(), params=[datetime_int, '002%', '300%', '%st%', i, batch_size])
|
||||
data = pd.read_sql(sql=sql_2, con=common.engine())
|
||||
data = data.drop_duplicates(subset="code", keep="last")
|
||||
print("########data[last_price]########:", len(data))
|
||||
stat_index_all(data, i)
|
||||
|
||||
|
||||
# 分批执行。
|
||||
def stat_index_all(data, idx):
|
||||
# print(data["last_price"])
|
||||
# 1), n天涨跌百分百计算
|
||||
# open price change (in percent) between today and the day before yesterday ‘r’ stands for rate.
|
||||
# stock[‘close_-2_r’]
|
||||
# 可以看到,-n天数据和今天数据的百分比。
|
||||
|
||||
|
||||
# 2), CR指标
|
||||
# http://wiki.mbalib.com/wiki/CR%E6%8C%87%E6%A0%87 价格动量指标
|
||||
# CR跌穿a、b、c、d四条线,再由低点向上爬升160时,为短线获利的一个良机,应适当卖出股票。
|
||||
# CR跌至40以下时,是建仓良机。而CR高于300~400时,应注意适当减仓。
|
||||
|
||||
# 3), KDJ指标
|
||||
# http://wiki.mbalib.com/wiki/%E9%9A%8F%E6%9C%BA%E6%8C%87%E6%A0%87
|
||||
# 随机指标(KDJ)一般是根据统计学的原理,通过一个特定的周期(常为9日、9周等)内出现过的最高价、
|
||||
# 最低价及最后一个计算周期的收盘价及这三者之间的比例关系,来计算最后一个计算周期的未成熟随机值RSV,
|
||||
# 然后根据平滑移动平均线的方法来计算K值、D值与J值,并绘成曲线图来研判股票走势。
|
||||
# (3)在使用中,常有J线的指标,即3乘以K值减2乘以D值(3K-2D=J),其目的是求出K值与D值的最大乖离程度,
|
||||
# 以领先KD值找出底部和头部。J大于100时为超买,小于10时为超卖。
|
||||
|
||||
# 4), MACD指标
|
||||
# http://wiki.mbalib.com/wiki/MACD
|
||||
# 平滑异同移动平均线(Moving Average Convergence Divergence,简称MACD指标),也称移动平均聚散指标
|
||||
# MACD 则可发挥其应有的功能,但当市场呈牛皮盘整格局,股价不上不下时,MACD买卖讯号较不明显。
|
||||
# 当用MACD作分析时,亦可运用其他的技术分析指标如短期 K,D图形作为辅助工具,而且也可对买卖讯号作双重的确认。
|
||||
|
||||
|
||||
# 5), BOLL指标
|
||||
# http://wiki.mbalib.com/wiki/BOLL
|
||||
# 布林线指标(Bollinger Bands)
|
||||
|
||||
# 6), RSI指标
|
||||
# http://wiki.mbalib.com/wiki/RSI
|
||||
# 相对强弱指标(Relative Strength Index,简称RSI),也称相对强弱指数、相对力度指数
|
||||
# (2)强弱指标保持高于50表示为强势市场,反之低于50表示为弱势市场。
|
||||
# (3)强弱指标多在70与30之间波动。当六日指标上升到达80时,表示股市已有超买现象,
|
||||
# 如果一旦继续上升,超过90以上时,则表示已到严重超买的警戒区,股价已形成头部,极可能在短期内反转回转。
|
||||
|
||||
|
||||
# 7), W%R指标
|
||||
# http://wiki.mbalib.com/wiki/%E5%A8%81%E5%BB%89%E6%8C%87%E6%A0%87
|
||||
# 威廉指数(Williams%Rate)该指数是利用摆动点来度量市场的超买超卖现象。
|
||||
|
||||
# 8), CCI指标
|
||||
# http://wiki.mbalib.com/wiki/%E9%A1%BA%E5%8A%BF%E6%8C%87%E6%A0%87
|
||||
# 顺势指标又叫CCI指标,其英文全称为“Commodity Channel Index”,
|
||||
# 是由美国股市分析家唐纳德·蓝伯特(Donald Lambert)所创造的,是一种重点研判股价偏离度的股市分析工具。
|
||||
# 1、当CCI指标从下向上突破﹢100线而进入非常态区间时,表明股价脱离常态而进入异常波动阶段,
|
||||
# 中短线应及时买入,如果有比较大的成交量配合,买入信号则更为可靠。
|
||||
# 2、当CCI指标从上向下突破﹣100线而进入另一个非常态区间时,表明股价的盘整阶段已经结束,
|
||||
# 将进入一个比较长的寻底过程,投资者应以持币观望为主。
|
||||
# CCI, default to 14 days
|
||||
|
||||
# 9), TR、ATR指标
|
||||
# http://wiki.mbalib.com/wiki/%E5%9D%87%E5%B9%85%E6%8C%87%E6%A0%87
|
||||
# 均幅指标(Average True Ranger,ATR)
|
||||
# 均幅指标(ATR)是取一定时间周期内的股价波动幅度的移动平均值,主要用于研判买卖时机。
|
||||
|
||||
# 10), DMA指标
|
||||
# http://wiki.mbalib.com/wiki/DMA
|
||||
# DMA指标(Different of Moving Average)又叫平行线差指标,是目前股市分析技术指标中的一种中短期指标,它常用于大盘指数和个股的研判。
|
||||
# DMA, difference of 10 and 50 moving average
|
||||
# stock[‘dma’]
|
||||
|
||||
# 11), DMI,+DI,-DI,DX,ADX,ADXR指标
|
||||
# http://wiki.mbalib.com/wiki/DMI
|
||||
# 动向指数Directional Movement Index,DMI)
|
||||
# http://wiki.mbalib.com/wiki/ADX
|
||||
# 平均趋向指标(Average Directional Indicator,简称ADX)
|
||||
# http://wiki.mbalib.com/wiki/%E5%B9%B3%E5%9D%87%E6%96%B9%E5%90%91%E6%8C%87%E6%95%B0%E8%AF%84%E4%BC%B0
|
||||
# 平均方向指数评估(ADXR)实际是今日ADX与前面某一日的ADX的平均值。ADXR在高位与ADX同步下滑,可以增加对ADX已经调头的尽早确认。
|
||||
# ADXR是ADX的附属产品,只能发出一种辅助和肯定的讯号,并非入市的指标,而只需同时配合动向指标(DMI)的趋势才可作出买卖策略。
|
||||
# 在应用时,应以ADX为主,ADXR为辅。
|
||||
|
||||
# 12), TRIX,MATRIX指标
|
||||
# http://wiki.mbalib.com/wiki/TRIX
|
||||
# TRIX指标又叫三重指数平滑移动平均指标(Triple Exponentially Smoothed Average)
|
||||
|
||||
# 13), VR,MAVR指标
|
||||
# http://wiki.mbalib.com/wiki/%E6%88%90%E4%BA%A4%E9%87%8F%E6%AF%94%E7%8E%87
|
||||
# 成交量比率(Volumn Ratio,VR)(简称VR),是一项通过分析股价上升日成交额(或成交量,下同)与股价下降日成交额比值,
|
||||
# 从而掌握市场买卖气势的中期技术指标。
|
||||
|
||||
#stock_column = ['adx', 'adxr', 'boll', 'boll_lb', 'boll_ub', 'cci', 'cci_20', 'close_-1_r',
|
||||
# 'close_-2_r', 'code', 'cr', 'cr-ma1', 'cr-ma2', 'cr-ma3', 'date', 'dma', 'dx',
|
||||
# 'kdjd', 'kdjj', 'kdjk', 'macd', 'macdh', 'macds', 'pdi',
|
||||
# 'rsi_12', 'rsi_6', 'trix', 'trix_9_sma', 'vr', 'vr_6_sma', 'wr_10', 'wr_6']
|
||||
|
||||
stock_column = ['date','code', 'boll', 'boll_lb', 'boll_ub',
|
||||
'kdjd', 'kdjj', 'kdjk', 'macd', 'macdh', 'macds', 'pdi',
|
||||
'trix', 'trix_9_sma', 'vr', 'vr_6_sma', 'wr_10', 'wr_6']
|
||||
# code cr cr-ma1 cr-ma2 cr-ma3 date
|
||||
|
||||
data_new = concat_guess_data(stock_column, data)
|
||||
|
||||
data_new = data_new.round(2) # 数据保留2位小数
|
||||
|
||||
# print(data_new.head())
|
||||
print("########insert db guess_indicators_daily idx :########:", idx)
|
||||
try:
|
||||
common.insert_db(data_new, "guess_indicators_daily", False, "`date`,`code`")
|
||||
except Exception as e:
|
||||
print("error :", e)
|
||||
|
||||
|
||||
# 链接guess 数据。
|
||||
def concat_guess_data(stock_column, data):
|
||||
# 使用 trade 填充数据
|
||||
print("stock_column:", stock_column)
|
||||
tmp_dic = {}
|
||||
# 循环增加临时数据。如果要是date,和code,
|
||||
for col in stock_column:
|
||||
if col == 'date':
|
||||
tmp_dic[col] = data["date"]
|
||||
elif col == 'code':
|
||||
tmp_dic[col] = data["code"]
|
||||
else:
|
||||
tmp_dic[col] = data["last_price"]
|
||||
# print("##########tmp_dic: ", tmp_dic)
|
||||
print("########################## BEGIN ##########################")
|
||||
stock_guess = pd.DataFrame(tmp_dic, index=data.index.values)
|
||||
print(stock_guess.columns.values)
|
||||
# print(stock_guess.head())
|
||||
stock_guess = stock_guess.apply(apply_guess, stock_column=stock_column, axis=1) # , axis=1)
|
||||
print(stock_guess.head())
|
||||
# stock_guess.astype('float32', copy=False)
|
||||
stock_guess.drop('date', axis=1, inplace=True) # 删除日期字段,然后和原始数据合并。
|
||||
# print(stock_guess["5d"])
|
||||
data_new = pd.merge(data, stock_guess, on=['code'], how='left')
|
||||
print("#############")
|
||||
return data_new
|
||||
|
||||
|
||||
# 带参数透传。
|
||||
def apply_guess(tmp, stock_column):
|
||||
# print("apply_guess columns args:", stock_column)
|
||||
# print("apply_guess data :", type(tmp))
|
||||
date = tmp["date"]
|
||||
code = tmp["code"]
|
||||
date_end = datetime.datetime.strptime(date, "%Y%m%d")
|
||||
date_start = (date_end + datetime.timedelta(days=-100)).strftime("%Y-%m-%d")
|
||||
date_end = date_end.strftime("%Y-%m-%d")
|
||||
# print(code, date_start, date_end)
|
||||
# open, high, close, low, volume, price_change, p_change, ma5, ma10, ma20, v_ma5, v_ma10, v_ma20, turnover
|
||||
# 使用缓存方法。加快计算速度。
|
||||
stock = common.get_hist_data_cache(code, date_start, date_end)
|
||||
# 设置返回数组。
|
||||
stock_data_list = []
|
||||
stock_name_list = []
|
||||
print(f"stock_column : {stock_column}")
|
||||
# 增加空判断,如果是空返回 0 数据。
|
||||
if stock is None:
|
||||
for col in stock_column:
|
||||
if col == 'date':
|
||||
stock_data_list.append(date)
|
||||
stock_name_list.append('date')
|
||||
elif col == 'code':
|
||||
stock_data_list.append(code)
|
||||
stock_name_list.append('code')
|
||||
else:
|
||||
stock_data_list.append(0)
|
||||
stock_name_list.append(col)
|
||||
return pd.Series(stock_data_list, index=stock_name_list)
|
||||
|
||||
# print(stock.head())
|
||||
# open high close low volume
|
||||
# stock = pd.DataFrame({"close": stock["close"]}, index=stock.index.values)
|
||||
# stock = stock.sort_index(0) # 将数据按照日期排序下。
|
||||
|
||||
stock["date"] = stock.index.values # 增加日期列。
|
||||
print(f"stock: {stock}")
|
||||
# stock = stock.sort_index(0) # 将数据按照日期排序下。
|
||||
# print(stock) [186 rows x 14 columns]
|
||||
# 初始化统计类
|
||||
# stockStat = stockstats.StockDataFrame.retype(pd.read_csv('002032.csv'))
|
||||
stockStat = stockstats.StockDataFrame.retype(stock)
|
||||
print(f"stockStat : {stockStat}")
|
||||
|
||||
print("########################## print result ##########################")
|
||||
for col in stock_column:
|
||||
if col == 'date':
|
||||
stock_data_list.append(date)
|
||||
stock_name_list.append('date')
|
||||
elif col == 'code':
|
||||
stock_data_list.append(code)
|
||||
stock_name_list.append('code')
|
||||
else:
|
||||
# 将数据的最后一个返回。
|
||||
print(col)
|
||||
print(stockStat[col])
|
||||
print(stockStat[col].values[1])
|
||||
#print(stockStat[col].head(1))
|
||||
|
||||
tmp_val = stockStat[col].values[1]
|
||||
if np.isinf(tmp_val): # 解决值中存在INF问题。
|
||||
tmp_val = 0
|
||||
if np.isnan(tmp_val): # 解决值中存在NaN问题。
|
||||
tmp_val = 0
|
||||
# print("col name : ", col, tmp_val)
|
||||
stock_data_list.append(tmp_val)
|
||||
stock_name_list.append(col)
|
||||
# print(stock_data_list)
|
||||
return pd.Series(stock_data_list, index=stock_name_list)
|
||||
|
||||
|
||||
# print(stock["mov_vol"].tail())
|
||||
# print(stock["return"].tail())
|
||||
# print("stock[10d].tail(1)", stock["10d"].tail(1).values[0])
|
||||
# 10d 20d 5-10d 5-20d 5d 60d code date mov_vol return
|
||||
# tmp = list([stock["10d"].tail(1).values[0], stock["20d"].tail(1).values[0], stock["5-10d"].tail(1).values[0],
|
||||
# stock["5-20d"].tail(1).values[0], stock["5d"].tail(1).values[0], stock["60d"].tail(1).values[0],
|
||||
# code, date, stock["mov_vol"].tail(1).values[0], stock["return"].tail(1).values[0]])
|
||||
# # print(tmp)
|
||||
# return tmp
|
||||
|
||||
|
||||
# main函数入口
|
||||
if __name__ == '__main__':
|
||||
# 使用方法传递。
|
||||
tmp_datetime = common.run_with_args(stat_all_batch)
|
||||
# 二次筛选数据。直接计算买卖股票数据。
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
#!/usr/local/bin/python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
|
||||
import libs.common as common
|
||||
import pandas as pd
|
||||
import numpy as np
|
||||
import math
|
||||
import datetime
|
||||
import stockstats
|
||||
from sqlalchemy import text
|
||||
|
||||
# 设置卖出数据。
|
||||
def stat_all_lite_sell(tmp_datetime):
|
||||
datetime_str = (tmp_datetime).strftime("%Y-%m-%d")
|
||||
datetime_int = (tmp_datetime).strftime("%Y%m%d")
|
||||
print("datetime_str:", datetime_str)
|
||||
print("datetime_int:", datetime_int)
|
||||
|
||||
# 超卖区:K值在20以下,D值在30以下为超卖区。一般情况下,股价有可能上涨,反弹的可能性增大。局内人不应轻易抛出股票,局外人可寻机入场。
|
||||
# J大于100时为超买,小于10时为超卖。
|
||||
# 当六日强弱指标下降至20时,表示股市有超卖现象
|
||||
# 当CCI<﹣100时,表明股价已经进入另一个非常态区间——超卖区间,投资者可以逢低吸纳股票。
|
||||
sql_1 = text("""
|
||||
SELECT `date`,`code`,`name`,`last_price`,`change_percent`,`change_amount`,`volume`,`turnover`,
|
||||
`amplitude`,`high`,`low`,`open`,`closed`,`volume_ratio`,`turnover_rate`,
|
||||
`pe_ratio`,`pb_ratio`,`market_cap`,`circulating_market_cap`,`rise_speed`,
|
||||
`change_5min`,`change_ercent_60day`,`ytd_change_percent`,
|
||||
`boll`, `boll_lb`, `boll_ub`, `kdjd`, `kdjj`, `kdjk`, `macd`, `macdh`,
|
||||
`macds`, `pdi`,`trix`, `trix_9_sma`, `vr`, `vr_6_sma`, `wr_10`, `wr_6`
|
||||
FROM stock_data.guess_indicators_daily WHERE `date` = :datetime
|
||||
and kdjk <= 20 and kdjd <= 30 and kdjj <= 10
|
||||
""")
|
||||
|
||||
try:
|
||||
# 删除老数据。
|
||||
del_sql = " DELETE FROM `stock_data`.`guess_indicators_lite_sell_daily` WHERE `date`= '%s' " % datetime_int
|
||||
common.insert(del_sql)
|
||||
except Exception as e:
|
||||
print("error :", e)
|
||||
|
||||
# 查询参数
|
||||
params = {"datetime": datetime_int}
|
||||
print(sql_1)
|
||||
data = pd.read_sql(sql=sql_1, con=common.engine(), params=params)
|
||||
data = data.drop_duplicates(subset="code", keep="last")
|
||||
print("######## stat_all_lite_sell len data ########:", len(data))
|
||||
|
||||
try:
|
||||
common.insert_db(data, "guess_indicators_lite_sell_daily", False, "`date`,`code`")
|
||||
except Exception as e:
|
||||
print("error :", e)
|
||||
|
||||
|
||||
|
||||
# main函数入口
|
||||
if __name__ == '__main__':
|
||||
# 使用方法传递。
|
||||
# 二次筛选数据。直接计算买卖股票数据。
|
||||
tmp_datetime = common.run_with_args(stat_all_lite_sell)
|
||||
|
||||
@@ -0,0 +1,480 @@
|
||||
#!/usr/local/bin/python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
|
||||
import libs.common as common
|
||||
import pandas as pd
|
||||
import numpy as np
|
||||
import math
|
||||
import datetime
|
||||
import stockstats
|
||||
|
||||
|
||||
### 对每日指标数据,进行筛选。将符合条件的。二次筛选出来。
|
||||
### 只是做简单筛选
|
||||
def stat_all_lite_buy(tmp_datetime):
|
||||
datetime_str = (tmp_datetime).strftime("%Y-%m-%d")
|
||||
datetime_int = (tmp_datetime).strftime("%Y%m%d")
|
||||
print("datetime_str:", datetime_str)
|
||||
print("datetime_int:", datetime_int)
|
||||
|
||||
# K值在80以上,D值在70以上,J值大于90时为超买。
|
||||
# J大于100时为超买,小于10时为超卖。
|
||||
# 当六日指标上升到达80时,表示股市已有超买现象
|
||||
# 当CCI>﹢100 时,表明股价已经进入非常态区间——超买区间,股价的异动现象应多加关注。
|
||||
sql_1 = """
|
||||
SELECT `date`, `code`, `name`, `changepercent`, `trade`, `open`, `high`, `low`,
|
||||
`settlement`, `volume`, `turnoverratio`, `amount`, `per`, `pb`, `mktcap`,
|
||||
`nmc` ,`kdjj`,`rsi_6`,`cci`
|
||||
FROM stock_data.guess_indicators_daily WHERE `date` = %s
|
||||
and kdjk >= 80 and kdjd >= 70 and kdjj >= 100 and rsi_6 >= 80 and cci >= 100
|
||||
""" # and kdjj > 100 and rsi_6 > 80 and cci > 100 # 调整参数,提前获得股票增长。
|
||||
|
||||
try:
|
||||
# 删除老数据。
|
||||
del_sql = " DELETE FROM `stock_data`.`guess_indicators_lite_buy_daily` WHERE `date`= '%s' " % datetime_int
|
||||
common.insert(del_sql)
|
||||
except Exception as e:
|
||||
print("error :", e)
|
||||
|
||||
data = pd.read_sql(sql=sql_1, con=common.engine(), params=[datetime_int])
|
||||
data = data.drop_duplicates(subset="code", keep="last")
|
||||
print("######## len data ########:", len(data))
|
||||
|
||||
try:
|
||||
common.insert_db(data, "guess_indicators_lite_buy_daily", False, "`date`,`code`")
|
||||
except Exception as e:
|
||||
print("error :", e)
|
||||
|
||||
# 设置卖出数据。
|
||||
def stat_all_lite_sell(tmp_datetime):
|
||||
datetime_str = (tmp_datetime).strftime("%Y-%m-%d")
|
||||
datetime_int = (tmp_datetime).strftime("%Y%m%d")
|
||||
print("datetime_str:", datetime_str)
|
||||
print("datetime_int:", datetime_int)
|
||||
|
||||
# 超卖区:K值在20以下,D值在30以下为超卖区。一般情况下,股价有可能上涨,反弹的可能性增大。局内人不应轻易抛出股票,局外人可寻机入场。
|
||||
# J大于100时为超买,小于10时为超卖。
|
||||
# 当六日强弱指标下降至20时,表示股市有超卖现象
|
||||
# 当CCI<﹣100时,表明股价已经进入另一个非常态区间——超卖区间,投资者可以逢低吸纳股票。
|
||||
sql_1 = """
|
||||
SELECT `date`, `code`, `name`, `changepercent`, `trade`, `open`, `high`, `low`,
|
||||
`settlement`, `volume`, `turnoverratio`, `amount`, `per`, `pb`, `mktcap`,
|
||||
`nmc` ,`kdjj`,`rsi_6`,`cci`
|
||||
FROM stock_data.guess_indicators_daily WHERE `date` = %s
|
||||
and kdjk <= 20 and kdjd <= 30 and kdjj <= 10 and rsi_6 <= 20 and cci <= -100
|
||||
"""
|
||||
|
||||
try:
|
||||
# 删除老数据。
|
||||
del_sql = " DELETE FROM `stock_data`.`guess_indicators_lite_sell_daily` WHERE `date`= '%s' " % datetime_int
|
||||
common.insert(del_sql)
|
||||
except Exception as e:
|
||||
print("error :", e)
|
||||
|
||||
data = pd.read_sql(sql=sql_1, con=common.engine(), params=[datetime_int])
|
||||
data = data.drop_duplicates(subset="code", keep="last")
|
||||
print("######## len data ########:", len(data))
|
||||
|
||||
try:
|
||||
common.insert_db(data, "guess_indicators_lite_sell_daily", False, "`date`,`code`")
|
||||
except Exception as e:
|
||||
print("error :", e)
|
||||
|
||||
# 批处理数据。
|
||||
def stat_all_batch(tmp_datetime):
|
||||
datetime_str = (tmp_datetime).strftime("%Y-%m-%d")
|
||||
datetime_int = (tmp_datetime).strftime("%Y%m%d")
|
||||
print("datetime_str:", datetime_str)
|
||||
print("datetime_int:", datetime_int)
|
||||
|
||||
try:
|
||||
# 删除老数据。
|
||||
del_sql = " DELETE FROM `stock_data`.`guess_indicators_daily` WHERE `date`= %s " % datetime_int
|
||||
common.insert(del_sql)
|
||||
except Exception as e:
|
||||
print("error :", e)
|
||||
|
||||
sql_count = """
|
||||
SELECT count(1) FROM stock_data.ts_today_all WHERE `date` = %s and `trade` > 0 and `open` > 0 and trade <= 20
|
||||
and `code` not like %s and `name` not like %s
|
||||
"""
|
||||
# 修改逻辑,增加中小板块计算。 中小板:002,创业板:300 。and `code` not like %s and `code` not like %s and `name` not like %s
|
||||
# count = common.select_count(sql_count, params=[datetime_int, '002%', '300%', '%st%'])
|
||||
count = common.select_count(sql_count, params=[datetime_int, '300%', '%st%'])
|
||||
print("count :", count)
|
||||
batch_size = 100
|
||||
end = int(math.ceil(float(count) / batch_size) * batch_size)
|
||||
print(end)
|
||||
for i in range(0, end, batch_size):
|
||||
print("loop :", i)
|
||||
# 查询今日满足股票数据。剔除数据:创业板股票数据,中小板股票数据,所有st股票
|
||||
# #`code` not like '002%' and `code` not like '300%' and `name` not like '%st%'
|
||||
sql_1 = """
|
||||
SELECT `date`, `code`, `name`, `changepercent`, `trade`, `open`, `high`, `low`,
|
||||
`settlement`, `volume`, `turnoverratio`, `amount`, `per`, `pb`, `mktcap`, `nmc`
|
||||
FROM stock_data.ts_today_all WHERE `date` = %s and `trade` > 0 and `open` > 0 and trade <= 20
|
||||
and `code` not like %s and `name` not like %s limit %s , %s
|
||||
"""
|
||||
print(sql_1)
|
||||
# data = pd.read_sql(sql=sql_1, con=common.engine(), params=[datetime_int, '002%', '300%', '%st%', i, batch_size])
|
||||
data = pd.read_sql(sql=sql_1, con=common.engine(), params=[datetime_int, '300%', '%st%', i, batch_size])
|
||||
data = data.drop_duplicates(subset="code", keep="last")
|
||||
print("########data[trade]########:", len(data))
|
||||
stat_index_all(data, i)
|
||||
|
||||
|
||||
# 分批执行。
|
||||
def stat_index_all(data, idx):
|
||||
# print(data["trade"])
|
||||
# 1), n天涨跌百分百计算
|
||||
# open price change (in percent) between today and the day before yesterday ‘r’ stands for rate.
|
||||
# stock[‘close_-2_r’]
|
||||
# 可以看到,-n天数据和今天数据的百分比。
|
||||
|
||||
|
||||
# 2), CR指标
|
||||
# http://wiki.mbalib.com/wiki/CR%E6%8C%87%E6%A0%87 价格动量指标
|
||||
# CR跌穿a、b、c、d四条线,再由低点向上爬升160时,为短线获利的一个良机,应适当卖出股票。
|
||||
# CR跌至40以下时,是建仓良机。而CR高于300~400时,应注意适当减仓。
|
||||
|
||||
# 3), KDJ指标
|
||||
# http://wiki.mbalib.com/wiki/%E9%9A%8F%E6%9C%BA%E6%8C%87%E6%A0%87
|
||||
# 随机指标(KDJ)一般是根据统计学的原理,通过一个特定的周期(常为9日、9周等)内出现过的最高价、
|
||||
# 最低价及最后一个计算周期的收盘价及这三者之间的比例关系,来计算最后一个计算周期的未成熟随机值RSV,
|
||||
# 然后根据平滑移动平均线的方法来计算K值、D值与J值,并绘成曲线图来研判股票走势。
|
||||
# (3)在使用中,常有J线的指标,即3乘以K值减2乘以D值(3K-2D=J),其目的是求出K值与D值的最大乖离程度,
|
||||
# 以领先KD值找出底部和头部。J大于100时为超买,小于10时为超卖。
|
||||
|
||||
# 4), MACD指标
|
||||
# http://wiki.mbalib.com/wiki/MACD
|
||||
# 平滑异同移动平均线(Moving Average Convergence Divergence,简称MACD指标),也称移动平均聚散指标
|
||||
# MACD 则可发挥其应有的功能,但当市场呈牛皮盘整格局,股价不上不下时,MACD买卖讯号较不明显。
|
||||
# 当用MACD作分析时,亦可运用其他的技术分析指标如短期 K,D图形作为辅助工具,而且也可对买卖讯号作双重的确认。
|
||||
|
||||
|
||||
# 5), BOLL指标
|
||||
# http://wiki.mbalib.com/wiki/BOLL
|
||||
# 布林线指标(Bollinger Bands)
|
||||
|
||||
# 6), RSI指标
|
||||
# http://wiki.mbalib.com/wiki/RSI
|
||||
# 相对强弱指标(Relative Strength Index,简称RSI),也称相对强弱指数、相对力度指数
|
||||
# (2)强弱指标保持高于50表示为强势市场,反之低于50表示为弱势市场。
|
||||
# (3)强弱指标多在70与30之间波动。当六日指标上升到达80时,表示股市已有超买现象,
|
||||
# 如果一旦继续上升,超过90以上时,则表示已到严重超买的警戒区,股价已形成头部,极可能在短期内反转回转。
|
||||
|
||||
|
||||
# 7), W%R指标
|
||||
# http://wiki.mbalib.com/wiki/%E5%A8%81%E5%BB%89%E6%8C%87%E6%A0%87
|
||||
# 威廉指数(Williams%Rate)该指数是利用摆动点来度量市场的超买超卖现象。
|
||||
|
||||
# 8), CCI指标
|
||||
# http://wiki.mbalib.com/wiki/%E9%A1%BA%E5%8A%BF%E6%8C%87%E6%A0%87
|
||||
# 顺势指标又叫CCI指标,其英文全称为“Commodity Channel Index”,
|
||||
# 是由美国股市分析家唐纳德·蓝伯特(Donald Lambert)所创造的,是一种重点研判股价偏离度的股市分析工具。
|
||||
# 1、当CCI指标从下向上突破﹢100线而进入非常态区间时,表明股价脱离常态而进入异常波动阶段,
|
||||
# 中短线应及时买入,如果有比较大的成交量配合,买入信号则更为可靠。
|
||||
# 2、当CCI指标从上向下突破﹣100线而进入另一个非常态区间时,表明股价的盘整阶段已经结束,
|
||||
# 将进入一个比较长的寻底过程,投资者应以持币观望为主。
|
||||
# CCI, default to 14 days
|
||||
|
||||
# 9), TR、ATR指标
|
||||
# http://wiki.mbalib.com/wiki/%E5%9D%87%E5%B9%85%E6%8C%87%E6%A0%87
|
||||
# 均幅指标(Average True Ranger,ATR)
|
||||
# 均幅指标(ATR)是取一定时间周期内的股价波动幅度的移动平均值,主要用于研判买卖时机。
|
||||
|
||||
# 10), DMA指标
|
||||
# http://wiki.mbalib.com/wiki/DMA
|
||||
# DMA指标(Different of Moving Average)又叫平行线差指标,是目前股市分析技术指标中的一种中短期指标,它常用于大盘指数和个股的研判。
|
||||
# DMA, difference of 10 and 50 moving average
|
||||
# stock[‘dma’]
|
||||
|
||||
# 11), DMI,+DI,-DI,DX,ADX,ADXR指标
|
||||
# http://wiki.mbalib.com/wiki/DMI
|
||||
# 动向指数Directional Movement Index,DMI)
|
||||
# http://wiki.mbalib.com/wiki/ADX
|
||||
# 平均趋向指标(Average Directional Indicator,简称ADX)
|
||||
# http://wiki.mbalib.com/wiki/%E5%B9%B3%E5%9D%87%E6%96%B9%E5%90%91%E6%8C%87%E6%95%B0%E8%AF%84%E4%BC%B0
|
||||
# 平均方向指数评估(ADXR)实际是今日ADX与前面某一日的ADX的平均值。ADXR在高位与ADX同步下滑,可以增加对ADX已经调头的尽早确认。
|
||||
# ADXR是ADX的附属产品,只能发出一种辅助和肯定的讯号,并非入市的指标,而只需同时配合动向指标(DMI)的趋势才可作出买卖策略。
|
||||
# 在应用时,应以ADX为主,ADXR为辅。
|
||||
|
||||
# 12), TRIX,MATRIX指标
|
||||
# http://wiki.mbalib.com/wiki/TRIX
|
||||
# TRIX指标又叫三重指数平滑移动平均指标(Triple Exponentially Smoothed Average)
|
||||
|
||||
# 13), VR,MAVR指标
|
||||
# http://wiki.mbalib.com/wiki/%E6%88%90%E4%BA%A4%E9%87%8F%E6%AF%94%E7%8E%87
|
||||
# 成交量比率(Volumn Ratio,VR)(简称VR),是一项通过分析股价上升日成交额(或成交量,下同)与股价下降日成交额比值,
|
||||
# 从而掌握市场买卖气势的中期技术指标。
|
||||
|
||||
stock_column = ['adx', 'adxr', 'boll', 'boll_lb', 'boll_ub', 'cci', 'cci_20', 'close_-1_r',
|
||||
'close_-2_r', 'code', 'cr', 'cr-ma1', 'cr-ma2', 'cr-ma3', 'date', 'dma', 'dx',
|
||||
'kdjd', 'kdjj', 'kdjk', 'macd', 'macdh', 'macds', 'mdi', 'pdi',
|
||||
'rsi_12', 'rsi_6', 'trix', 'trix_9_sma', 'vr', 'vr_6_sma', 'wr_10', 'wr_6']
|
||||
# code cr cr-ma1 cr-ma2 cr-ma3 date
|
||||
|
||||
data_new = concat_guess_data(stock_column, data)
|
||||
|
||||
data_new = data_new.round(2) # 数据保留2位小数
|
||||
|
||||
# print(data_new.head())
|
||||
print("########insert db guess_indicators_daily idx :########:", idx)
|
||||
try:
|
||||
common.insert_db(data_new, "guess_indicators_daily", False, "`date`,`code`")
|
||||
except Exception as e:
|
||||
print("error :", e)
|
||||
|
||||
|
||||
# 链接guess 数据。
|
||||
def concat_guess_data(stock_column, data):
|
||||
# 使用 trade 填充数据
|
||||
print("stock_column:", stock_column)
|
||||
tmp_dic = {}
|
||||
# 循环增加临时数据。如果要是date,和code,
|
||||
for col in stock_column:
|
||||
if col == 'date':
|
||||
tmp_dic[col] = data["date"]
|
||||
elif col == 'code':
|
||||
tmp_dic[col] = data["code"]
|
||||
else:
|
||||
tmp_dic[col] = data["trade"]
|
||||
# print("##########tmp_dic: ", tmp_dic)
|
||||
print("########################## BEGIN ##########################")
|
||||
stock_guess = pd.DataFrame(tmp_dic, index=data.index.values)
|
||||
print(stock_guess.columns.values)
|
||||
# print(stock_guess.head())
|
||||
stock_guess = stock_guess.apply(apply_guess, stock_column=stock_column, axis=1) # , axis=1)
|
||||
print(stock_guess.head())
|
||||
# stock_guess.astype('float32', copy=False)
|
||||
stock_guess.drop('date', axis=1, inplace=True) # 删除日期字段,然后和原始数据合并。
|
||||
# print(stock_guess["5d"])
|
||||
data_new = pd.merge(data, stock_guess, on=['code'], how='left')
|
||||
print("#############")
|
||||
return data_new
|
||||
|
||||
|
||||
# 带参数透传。
|
||||
def apply_guess(tmp, stock_column):
|
||||
# print("apply_guess columns args:", stock_column)
|
||||
# print("apply_guess data :", type(tmp))
|
||||
date = tmp["date"]
|
||||
code = tmp["code"]
|
||||
date_end = datetime.datetime.strptime(date, "%Y%m%d")
|
||||
date_start = (date_end + datetime.timedelta(days=-100)).strftime("%Y-%m-%d")
|
||||
date_end = date_end.strftime("%Y-%m-%d")
|
||||
# print(code, date_start, date_end)
|
||||
# open, high, close, low, volume, price_change, p_change, ma5, ma10, ma20, v_ma5, v_ma10, v_ma20, turnover
|
||||
# 使用缓存方法。加快计算速度。
|
||||
stock = common.get_hist_data_cache(code, date_start, date_end)
|
||||
# 设置返回数组。
|
||||
stock_data_list = []
|
||||
stock_name_list = []
|
||||
# 增加空判断,如果是空返回 0 数据。
|
||||
if stock is None:
|
||||
for col in stock_column:
|
||||
if col == 'date':
|
||||
stock_data_list.append(date)
|
||||
stock_name_list.append('date')
|
||||
elif col == 'code':
|
||||
stock_data_list.append(code)
|
||||
stock_name_list.append('code')
|
||||
else:
|
||||
stock_data_list.append(0)
|
||||
stock_name_list.append(col)
|
||||
return pd.Series(stock_data_list, index=stock_name_list)
|
||||
|
||||
# print(stock.head())
|
||||
# open high close low volume
|
||||
# stock = pd.DataFrame({"close": stock["close"]}, index=stock.index.values)
|
||||
stock = stock.sort_index(0) # 将数据按照日期排序下。
|
||||
|
||||
stock["date"] = stock.index.values # 增加日期列。
|
||||
stock = stock.sort_index(0) # 将数据按照日期排序下。
|
||||
# print(stock) [186 rows x 14 columns]
|
||||
# 初始化统计类
|
||||
# stockStat = stockstats.StockDataFrame.retype(pd.read_csv('002032.csv'))
|
||||
stockStat = stockstats.StockDataFrame.retype(stock)
|
||||
|
||||
print("########################## print result ##########################")
|
||||
for col in stock_column:
|
||||
if col == 'date':
|
||||
stock_data_list.append(date)
|
||||
stock_name_list.append('date')
|
||||
elif col == 'code':
|
||||
stock_data_list.append(code)
|
||||
stock_name_list.append('code')
|
||||
else:
|
||||
# 将数据的最后一个返回。
|
||||
tmp_val = stockStat[col].tail(1).values[0]
|
||||
if np.isinf(tmp_val): # 解决值中存在INF问题。
|
||||
tmp_val = 0
|
||||
if np.isnan(tmp_val): # 解决值中存在NaN问题。
|
||||
tmp_val = 0
|
||||
# print("col name : ", col, tmp_val)
|
||||
stock_data_list.append(tmp_val)
|
||||
stock_name_list.append(col)
|
||||
# print(stock_data_list)
|
||||
return pd.Series(stock_data_list, index=stock_name_list)
|
||||
|
||||
|
||||
# print(stock["mov_vol"].tail())
|
||||
# print(stock["return"].tail())
|
||||
# print("stock[10d].tail(1)", stock["10d"].tail(1).values[0])
|
||||
# 10d 20d 5-10d 5-20d 5d 60d code date mov_vol return
|
||||
# tmp = list([stock["10d"].tail(1).values[0], stock["20d"].tail(1).values[0], stock["5-10d"].tail(1).values[0],
|
||||
# stock["5-20d"].tail(1).values[0], stock["5d"].tail(1).values[0], stock["60d"].tail(1).values[0],
|
||||
# code, date, stock["mov_vol"].tail(1).values[0], stock["return"].tail(1).values[0]])
|
||||
# # print(tmp)
|
||||
# return tmp
|
||||
|
||||
|
||||
# main函数入口
|
||||
if __name__ == '__main__':
|
||||
# 使用方法传递。
|
||||
tmp_datetime = common.run_with_args(stat_all_batch)
|
||||
# 二次筛选数据。直接计算买卖股票数据。
|
||||
tmp_datetime = common.run_with_args(stat_all_lite_buy)
|
||||
tmp_datetime = common.run_with_args(stat_all_lite_sell)
|
||||
|
||||
|
||||
####################### 老方法,弃用了。#######################
|
||||
def stat_index_all_no_use(tmp_datetime):
|
||||
datetime_str = (tmp_datetime).strftime("%Y-%m-%d")
|
||||
datetime_int = (tmp_datetime).strftime("%Y%m%d")
|
||||
print("datetime_str:", datetime_str)
|
||||
print("datetime_int:", datetime_int)
|
||||
|
||||
# 查询今日满足股票数据。剔除数据:创业板股票数据,中小板股票数据,所有st股票
|
||||
# #`code` not like '002%' and `code` not like '300%' and `name` not like '%st%'
|
||||
sql_1 = """
|
||||
SELECT `date`, `code`, `name`, `changepercent`, `trade`, `open`, `high`, `low`,
|
||||
`settlement`, `volume`, `turnoverratio`, `amount`, `per`, `pb`, `mktcap`, `nmc`
|
||||
FROM stock_data.ts_today_all WHERE `date` = %s and `trade` > 0 and `open` > 0 and trade <= 20
|
||||
and `code` not like %s and `code` not like %s and `name` not like %s
|
||||
"""
|
||||
print(sql_1)
|
||||
data = pd.read_sql(sql=sql_1, con=common.engine(), params=[datetime_int, '002%', '300%', '%st%'])
|
||||
data = data.drop_duplicates(subset="code", keep="last")
|
||||
print("########data[trade]########:", len(data))
|
||||
# print(data["trade"])
|
||||
|
||||
# 1), n天涨跌百分百计算
|
||||
# open price change (in percent) between today and the day before yesterday ‘r’ stands for rate.
|
||||
# stock[‘close_-2_r’]
|
||||
# 可以看到,-n天数据和今天数据的百分比。
|
||||
stock_column = ['close_-1_r', 'close_-2_r', 'code', 'date'] # close_-1_r close_-2_r code date
|
||||
data_new = concat_guess_data(stock_column, data)
|
||||
|
||||
# 2), CR指标
|
||||
# http://wiki.mbalib.com/wiki/CR%E6%8C%87%E6%A0%87 价格动量指标
|
||||
# CR跌穿a、b、c、d四条线,再由低点向上爬升160时,为短线获利的一个良机,应适当卖出股票。
|
||||
# CR跌至40以下时,是建仓良机。而CR高于300~400时,应注意适当减仓。
|
||||
stock_column = ['code', 'cr', 'cr-ma1', 'cr-ma2', 'cr-ma3', 'date'] # code cr cr-ma1 cr-ma2 cr-ma3 date
|
||||
data_new = concat_guess_data(stock_column, data_new)
|
||||
|
||||
# 3), KDJ指标
|
||||
# http://wiki.mbalib.com/wiki/%E9%9A%8F%E6%9C%BA%E6%8C%87%E6%A0%87
|
||||
# 随机指标(KDJ)一般是根据统计学的原理,通过一个特定的周期(常为9日、9周等)内出现过的最高价、
|
||||
# 最低价及最后一个计算周期的收盘价及这三者之间的比例关系,来计算最后一个计算周期的未成熟随机值RSV,
|
||||
# 然后根据平滑移动平均线的方法来计算K值、D值与J值,并绘成曲线图来研判股票走势。
|
||||
# (3)在使用中,常有J线的指标,即3乘以K值减2乘以D值(3K-2D=J),其目的是求出K值与D值的最大乖离程度,
|
||||
# 以领先KD值找出底部和头部。J大于100时为超买,小于10时为超卖。
|
||||
stock_column = ['code', 'date', 'kdjd', 'kdjj', 'kdjk'] # code date kdjd kdjj kdjk
|
||||
data_new = concat_guess_data(stock_column, data_new)
|
||||
|
||||
# 4), MACD指标
|
||||
# http://wiki.mbalib.com/wiki/MACD
|
||||
# 平滑异同移动平均线(Moving Average Convergence Divergence,简称MACD指标),也称移动平均聚散指标
|
||||
# MACD 则可发挥其应有的功能,但当市场呈牛皮盘整格局,股价不上不下时,MACD买卖讯号较不明显。
|
||||
# 当用MACD作分析时,亦可运用其他的技术分析指标如短期 K,D图形作为辅助工具,而且也可对买卖讯号作双重的确认。
|
||||
stock_column = ['code', 'date', 'macd', 'macdh', 'macds'] # code date macd macdh macds
|
||||
data_new = concat_guess_data(stock_column, data_new)
|
||||
|
||||
# 5), BOLL指标
|
||||
# http://wiki.mbalib.com/wiki/BOLL
|
||||
# 布林线指标(Bollinger Bands)
|
||||
stock_column = ['boll', 'boll_lb', 'boll_ub', 'code', 'date'] # boll boll_lb boll_ub code date
|
||||
data_new = concat_guess_data(stock_column, data_new)
|
||||
|
||||
# 6), RSI指标
|
||||
# http://wiki.mbalib.com/wiki/RSI
|
||||
# 相对强弱指标(Relative Strength Index,简称RSI),也称相对强弱指数、相对力度指数
|
||||
# (2)强弱指标保持高于50表示为强势市场,反之低于50表示为弱势市场。
|
||||
# (3)强弱指标多在70与30之间波动。当六日指标上升到达80时,表示股市已有超买现象,
|
||||
# 如果一旦继续上升,超过90以上时,则表示已到严重超买的警戒区,股价已形成头部,极可能在短期内反转回转。
|
||||
stock_column = ['code', 'date', 'rsi_12', 'rsi_6'] # code date rsi_12 rsi_6
|
||||
data_new = concat_guess_data(stock_column, data_new)
|
||||
|
||||
# 7), W%R指标
|
||||
# http://wiki.mbalib.com/wiki/%E5%A8%81%E5%BB%89%E6%8C%87%E6%A0%87
|
||||
# 威廉指数(Williams%Rate)该指数是利用摆动点来度量市场的超买超卖现象。
|
||||
stock_column = ['code', 'date', 'wr_10', 'wr_6'] # code date wr_10 wr_6
|
||||
data_new = concat_guess_data(stock_column, data_new)
|
||||
|
||||
# 8), CCI指标
|
||||
# http://wiki.mbalib.com/wiki/%E9%A1%BA%E5%8A%BF%E6%8C%87%E6%A0%87
|
||||
# 顺势指标又叫CCI指标,其英文全称为“Commodity Channel Index”,
|
||||
# 是由美国股市分析家唐纳德·蓝伯特(Donald Lambert)所创造的,是一种重点研判股价偏离度的股市分析工具。
|
||||
# 1、当CCI指标从下向上突破﹢100线而进入非常态区间时,表明股价脱离常态而进入异常波动阶段,
|
||||
# 中短线应及时买入,如果有比较大的成交量配合,买入信号则更为可靠。
|
||||
# 2、当CCI指标从上向下突破﹣100线而进入另一个非常态区间时,表明股价的盘整阶段已经结束,
|
||||
# 将进入一个比较长的寻底过程,投资者应以持币观望为主。
|
||||
# CCI, default to 14 days
|
||||
stock_column = ['cci', 'cci_20', 'code', 'date'] # cci cci_20 code date
|
||||
data_new = concat_guess_data(stock_column, data_new)
|
||||
|
||||
# 9), TR、ATR指标
|
||||
# http://wiki.mbalib.com/wiki/%E5%9D%87%E5%B9%85%E6%8C%87%E6%A0%87
|
||||
# 均幅指标(Average True Ranger,ATR)
|
||||
# 均幅指标(ATR)是取一定时间周期内的股价波动幅度的移动平均值,主要用于研判买卖时机。
|
||||
stock_column = ['cci', 'cci_20', 'code', 'date'] # cci cci_20 code date
|
||||
data_new = concat_guess_data(stock_column, data_new)
|
||||
|
||||
# 10), DMA指标
|
||||
# http://wiki.mbalib.com/wiki/DMA
|
||||
# DMA指标(Different of Moving Average)又叫平行线差指标,是目前股市分析技术指标中的一种中短期指标,它常用于大盘指数和个股的研判。
|
||||
# DMA, difference of 10 and 50 moving average
|
||||
# stock[‘dma’]
|
||||
stock_column = ['code', 'date', 'dma'] # code date dma
|
||||
data_new = concat_guess_data(stock_column, data_new)
|
||||
|
||||
# 11), DMI,+DI,-DI,DX,ADX,ADXR指标
|
||||
# http://wiki.mbalib.com/wiki/DMI
|
||||
# 动向指数Directional Movement Index,DMI)
|
||||
# http://wiki.mbalib.com/wiki/ADX
|
||||
# 平均趋向指标(Average Directional Indicator,简称ADX)
|
||||
# http://wiki.mbalib.com/wiki/%E5%B9%B3%E5%9D%87%E6%96%B9%E5%90%91%E6%8C%87%E6%95%B0%E8%AF%84%E4%BC%B0
|
||||
# 平均方向指数评估(ADXR)实际是今日ADX与前面某一日的ADX的平均值。ADXR在高位与ADX同步下滑,可以增加对ADX已经调头的尽早确认。
|
||||
# ADXR是ADX的附属产品,只能发出一种辅助和肯定的讯号,并非入市的指标,而只需同时配合动向指标(DMI)的趋势才可作出买卖策略。
|
||||
# 在应用时,应以ADX为主,ADXR为辅。
|
||||
stock_column = ['adx', 'adxr', 'code', 'date', 'dx', 'mdi',
|
||||
'pdi'] # adx adxr code date dx mdi pdi
|
||||
data_new = concat_guess_data(stock_column, data_new)
|
||||
|
||||
# 12), TRIX,MATRIX指标
|
||||
# http://wiki.mbalib.com/wiki/TRIX
|
||||
# TRIX指标又叫三重指数平滑移动平均指标(Triple Exponentially Smoothed Average)
|
||||
stock_column = ['code', 'date', 'trix', 'trix_9_sma'] # code date trix trix_9_sma
|
||||
data_new = concat_guess_data(stock_column, data_new)
|
||||
|
||||
# 13), VR,MAVR指标
|
||||
# http://wiki.mbalib.com/wiki/%E6%88%90%E4%BA%A4%E9%87%8F%E6%AF%94%E7%8E%87
|
||||
# 成交量比率(Volumn Ratio,VR)(简称VR),是一项通过分析股价上升日成交额(或成交量,下同)与股价下降日成交额比值,
|
||||
# 从而掌握市场买卖气势的中期技术指标。
|
||||
stock_column = ['code', 'date', 'vr', 'vr_6_sma'] # code date vr vr_6_sma
|
||||
data_new = concat_guess_data(stock_column, data_new)
|
||||
|
||||
data_new = data_new.round(2) # 数据保留2位小数
|
||||
|
||||
# 删除老数据。
|
||||
del_sql = " DELETE FROM `stock_data`.`guess_indicators_daily` WHERE `date`= %s " % datetime_int
|
||||
common.insert(del_sql)
|
||||
|
||||
# print(data_new.head())
|
||||
# data_new["down_rate"] = (data_new["trade"] - data_new["wave_mean"]) / data_new["wave_base"]
|
||||
common.insert_db(data_new, "guess_indicators_daily", False, "`date`,`code`")
|
||||
|
||||
# 进行左连接.
|
||||
# tmp = pd.merge(tmp, tmp2, on=['company_id'], how='left')
|
||||
@@ -0,0 +1,89 @@
|
||||
#!/usr/local/bin/python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
|
||||
import libs.common as common
|
||||
import sys
|
||||
import time
|
||||
import pandas as pd
|
||||
import tushare as ts
|
||||
from sqlalchemy.types import NVARCHAR
|
||||
from sqlalchemy import inspect
|
||||
import datetime
|
||||
|
||||
|
||||
# 增加一个新quarter列,用来存储季度信息。
|
||||
def concat_quarter(year, quarter, data_array):
|
||||
print(len(data_array))
|
||||
quarter_str = str(year) + str("%02d" % quarter) # 格式化季度数据。2位。
|
||||
# 增加到列。
|
||||
quarter_col = pd.DataFrame([quarter_str for _ in range(len(data_array))], columns=["quarter"])
|
||||
return pd.concat([quarter_col, data_array], axis=1)
|
||||
|
||||
|
||||
#############################基本面数据 http://tushare.org/fundamental.html
|
||||
def stat_all(tmp_datetime):
|
||||
# 返回 31 天前的数据,做上个季度数据统计。
|
||||
tmp_datetime_1month = tmp_datetime + datetime.timedelta(days=-31)
|
||||
year = int((tmp_datetime_1month).strftime("%Y"))
|
||||
quarter = int(pd.Timestamp(tmp_datetime_1month).quarter) # 获得上个季度的数据。
|
||||
print("############ year %d, quarter %d", year, quarter)
|
||||
# 业绩报告(主表)
|
||||
data = ts.get_report_data(year, quarter)
|
||||
# 增加季度字段。
|
||||
data = concat_quarter(year, quarter, data)
|
||||
# 处理重复数据,保存最新一条数据。最后一步处理,否则concat有问题。
|
||||
data = data.drop_duplicates(subset="code", keep="last")
|
||||
# 插入数据库。
|
||||
common.insert_db(data, "ts_report_data", False, "`quarter`,`code`")
|
||||
|
||||
# 盈利能力
|
||||
data = ts.get_profit_data(year, quarter)
|
||||
# 增加季度字段。
|
||||
data = concat_quarter(year, quarter, data)
|
||||
# 处理重复数据,保存最新一条数据。
|
||||
data = data.drop_duplicates(subset="code", keep="last")
|
||||
# 插入数据库。
|
||||
common.insert_db(data, "ts_profit_data", False, "`quarter`,`code`")
|
||||
|
||||
# 营运能力
|
||||
data = ts.get_operation_data(year, quarter)
|
||||
# 增加季度字段。
|
||||
data = concat_quarter(year, quarter, data)
|
||||
# 处理重复数据,保存最新一条数据。最后一步处理,否则concat有问题。
|
||||
data = data.drop_duplicates(subset="code", keep="last")
|
||||
# 插入数据库。
|
||||
common.insert_db(data, "ts_operation_data", False, "`quarter`,`code`")
|
||||
|
||||
# 成长能力
|
||||
data = ts.get_growth_data(year, quarter)
|
||||
# 增加季度字段。
|
||||
data = concat_quarter(year, quarter, data)
|
||||
# 处理重复数据,保存最新一条数据。最后一步处理,否则concat有问题。
|
||||
data = data.drop_duplicates(subset="code", keep="last")
|
||||
# 插入数据库。
|
||||
common.insert_db(data, "ts_growth_data", False, "`quarter`,`code`")
|
||||
|
||||
# 偿债能力
|
||||
data = ts.get_debtpaying_data(year, quarter)
|
||||
# 增加季度字段。
|
||||
data = concat_quarter(year, quarter, data)
|
||||
# 处理重复数据,保存最新一条数据。最后一步处理,否则concat有问题。
|
||||
data = data.drop_duplicates(subset="code", keep="last")
|
||||
# 插入数据库。
|
||||
common.insert_db(data, "ts_debtpaying_data", False, "`quarter`,`code`")
|
||||
|
||||
# 现金流量
|
||||
data = ts.get_cashflow_data(year, quarter)
|
||||
# 增加季度字段。
|
||||
data = concat_quarter(year, quarter, data)
|
||||
# 处理重复数据,保存最新一条数据。最后一步处理,否则concat有问题。
|
||||
data = data.drop_duplicates(subset="code", keep="last")
|
||||
# 插入数据库。
|
||||
common.insert_db(data, "ts_cashflow_data", False, "`quarter`,`code`")
|
||||
|
||||
|
||||
# main函数入口
|
||||
if __name__ == '__main__':
|
||||
# 使用方法传递。
|
||||
tmp_datetime = common.run_with_args(stat_all)
|
||||
Executable
+5
@@ -0,0 +1,5 @@
|
||||
#!/bin/sh
|
||||
|
||||
ps -ef | grep 'tensorflow_model_server' | grep -v grep | awk '{print$2}' | xargs kill -9
|
||||
echo "" > /data/logs/mnist_serving.log
|
||||
nohup tensorflow_model_server --model_name=mnist --model_base_path=/data/mnist_model >> /data/logs/mnist_serving.log &
|
||||
Executable
+4
@@ -0,0 +1,4 @@
|
||||
#!/bin/sh
|
||||
|
||||
ps -ef | grep python3 | grep '/data/stock/web/main.py' | awk '{print$2}' | xargs kill -9
|
||||
echo "restart web ... " > /data/logs/tornado.log
|
||||
Executable
+25
@@ -0,0 +1,25 @@
|
||||
#!/bin/sh
|
||||
|
||||
export PYTHONIOENCODING=utf-8
|
||||
export LANG=zh_CN.UTF-8
|
||||
export PYTHONPATH=/data/stock
|
||||
export LC_CTYPE=zh_CN.UTF-8
|
||||
|
||||
mkdir -p /data/logs/tensorflow
|
||||
|
||||
|
||||
|
||||
DATE=`date +%Y-%m-%d:%H:%M:%S`
|
||||
|
||||
echo $DATE >> /data/logs/run_cron.log
|
||||
|
||||
# 解决定时任务不启动问题,因为权限导致
|
||||
chmod 755 /etc/cron.minutely/* && chmod 755 /etc/cron.hourly/*
|
||||
chmod 755 /etc/cron.daily/* && chmod 755 /etc/cron.monthly/*
|
||||
|
||||
# 配置文件每次都设置权限
|
||||
chmod 600 /var/spool/cron/crontabs/root
|
||||
chown root:root /var/spool/cron/crontabs/root
|
||||
|
||||
#启动cron服务。在前台
|
||||
/usr/sbin/cron -f
|
||||
Executable
+29
@@ -0,0 +1,29 @@
|
||||
#!/bin/sh
|
||||
|
||||
export PYTHONIOENCODING=utf-8
|
||||
export LANG=zh_CN.UTF-8
|
||||
export PYTHONPATH=/data/stock
|
||||
export LC_CTYPE=zh_CN.UTF-8
|
||||
|
||||
mkdir -p /data/logs/tensorflow
|
||||
|
||||
|
||||
|
||||
DATE=`date +%Y-%m-%d:%H:%M:%S`
|
||||
|
||||
echo $DATE >> /data/logs/run_init.log
|
||||
|
||||
echo "wait 120 second , mysqldb is starting ." >> /data/logs/run_init.log
|
||||
sleep 120
|
||||
|
||||
/usr/local/bin/python3 /data/stock/jobs/basic_job.py >> /data/logs/run_init.log
|
||||
|
||||
# https://stackoverflow.com/questions/27771781/how-can-i-access-docker-set-environment-variables-from-a-cron-job
|
||||
# 解决环境变量输出问题。
|
||||
printenv | grep -v "no_proxy" >> /etc/environment
|
||||
|
||||
# 第一次后台执行日数据。
|
||||
nohup bash /data/stock/jobs/cron.daily/run_daily &
|
||||
|
||||
#防止 supervisor 重复执行
|
||||
sleep 999999d
|
||||
Executable
+6
@@ -0,0 +1,6 @@
|
||||
#!/bin/sh
|
||||
|
||||
mkdir -p /data/notebooks
|
||||
|
||||
/usr/local/bin/jupyter notebook --NotebookApp.notebook_dir='/data/notebooks' --ip=0.0.0.0 \
|
||||
--allow-root >> /data/logs/jupyter-notebook.log
|
||||
Executable
+9
@@ -0,0 +1,9 @@
|
||||
#!/bin/bash
|
||||
|
||||
export PYTHONIOENCODING=utf-8
|
||||
export LANG=zh_CN.UTF-8
|
||||
export PYTHONPATH=/data/stock
|
||||
export LC_CTYPE=zh_CN.UTF-8
|
||||
|
||||
echo "" > /data/logs/web.log
|
||||
/usr/local/bin/python3 /data/stock/web/main.py -log_file_prefix=/data/logs/web.log
|
||||
Executable
+12
@@ -0,0 +1,12 @@
|
||||
#!/bin/sh
|
||||
|
||||
DATE=`date +%Y-%m-%d:%H:%M:%S`
|
||||
echo $DATE
|
||||
|
||||
if [ ! -d "/data/mariadb" ]; then
|
||||
mkdir -p /data/mariadb
|
||||
/usr/bin/mysql_install_db
|
||||
fi
|
||||
|
||||
|
||||
/usr/bin/mysqld_safe >> /data/logs/start_mariadb.log
|
||||
@@ -0,0 +1,27 @@
|
||||
#!/usr/local/bin/python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import akshare as ak
|
||||
import libs.common as common
|
||||
|
||||
print(ak.__version__)
|
||||
|
||||
# 历史行情数据
|
||||
# 日频率
|
||||
# 接口: stock_zh_a_daily
|
||||
# 目标地址: https://finance.sina.com.cn/realstock/company/sh600006/nc.shtml(示例)
|
||||
# 描述: A 股数据是从新浪财经获取的数据, 历史数据按日频率更新; 注意其中的 sh689009 为 CDR, 请 通过 stock_zh_a_cdr_daily 接口获取
|
||||
# 限量: 单次返回指定 A 股上市公司指定日期间的历史行情日频率数据
|
||||
# adjust=""; 默认为空: 返回不复权的数据; qfq: 返回前复权后的数据; hfq: 返回后复权后的数据;
|
||||
|
||||
stock_zh_a_daily_qfq_df = ak.stock_zh_a_daily(symbol="sz000002", adjust="")
|
||||
print(stock_zh_a_daily_qfq_df)
|
||||
|
||||
stock_zh_a_daily_qfq_df = ak.stock_zh_a_daily(symbol="sz000002", start_date="20200101", end_date="20210101", adjust="")
|
||||
print(stock_zh_a_daily_qfq_df)
|
||||
|
||||
# 插入到 MySQL 数据库中
|
||||
common.insert_db(stock_zh_a_daily_qfq_df, "stock_zh_a_daily", True, "`symbol`")
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
#!/usr/local/bin/python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import akshare as ak
|
||||
import libs.common as common
|
||||
|
||||
print(ak.__version__)
|
||||
|
||||
# 实时行情数据
|
||||
# 接口: stock_zh_a_spot
|
||||
# 目标地址: http://vip.stock.finance.sina.com.cn/mkt/#hs_a
|
||||
# 描述: A 股数据是从新浪财经获取的数据, 重复运行本函数会被新浪暂时封 IP, 建议增加时间间隔
|
||||
# 限量: 单次返回所有 A 股上市公司的实时行情数据
|
||||
|
||||
stock_zh_a_spot_df = ak.stock_zh_a_spot()
|
||||
print(stock_zh_a_spot_df)
|
||||
|
||||
# 插入到 MySQL 数据库中
|
||||
common.insert_db(stock_zh_a_spot_df, "stock_zh_a_spot", True, "`symbol`")
|
||||
@@ -0,0 +1,20 @@
|
||||
#!/usr/local/bin/python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import akshare as ak
|
||||
import libs.common as common
|
||||
|
||||
print(ak.__version__)
|
||||
|
||||
#stock_sse_summary_df = ak.stock_sse_summary()
|
||||
#print(stock_sse_summary_df)
|
||||
|
||||
# 接口: stock_zh_index_spot
|
||||
# 目标地址: http://vip.stock.finance.sina.com.cn/mkt/#hs_s
|
||||
# 描述: 中国股票指数数据, 注意该股票指数指新浪提供的国内股票指数
|
||||
# 限量: 单次返回所有指数的实时行情数据
|
||||
stock_zh_index_spot_df = ak.stock_zh_index_spot()
|
||||
print(stock_zh_index_spot_df)
|
||||
|
||||
# 插入到 MySQL 数据库中
|
||||
common.insert_db(stock_zh_index_spot_df, "stock_zh_index_spot_df", True, "`symbol`")
|
||||
@@ -0,0 +1,242 @@
|
||||
#!/usr/local/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# apk add py-mysqldb or
|
||||
|
||||
import platform
|
||||
import datetime
|
||||
import time
|
||||
import sys
|
||||
import os
|
||||
import MySQLdb
|
||||
from sqlalchemy import create_engine
|
||||
from sqlalchemy.types import NVARCHAR
|
||||
from sqlalchemy import inspect
|
||||
import pandas as pd
|
||||
import traceback
|
||||
import akshare as ak
|
||||
|
||||
# 使用环境变量获得数据库。兼容开发模式可docker模式。
|
||||
MYSQL_HOST = os.environ.get('MYSQL_HOST') if (os.environ.get('MYSQL_HOST') != None) else "mysqldb"
|
||||
MYSQL_USER = os.environ.get('MYSQL_USER') if (os.environ.get('MYSQL_USER') != None) else "root"
|
||||
MYSQL_PWD = os.environ.get('MYSQL_PWD') if (os.environ.get('MYSQL_PWD') != None) else "mysqldb"
|
||||
MYSQL_DB = os.environ.get('MYSQL_DB') if (os.environ.get('MYSQL_DB') != None) else "stock_data"
|
||||
MYSQL_PORT = os.environ.get('MYSQL_PORT') if (os.environ.get('MYSQL_PORT') != None) else "3306"
|
||||
|
||||
print("MYSQL_HOST :", MYSQL_HOST, ",MYSQL_USER :", MYSQL_USER, ",MYSQL_DB :", MYSQL_DB)
|
||||
MYSQL_CONN_URL = "mysql+mysqldb://" + MYSQL_USER + ":" + MYSQL_PWD + "@" + MYSQL_HOST + ":" + MYSQL_PORT + "/" + MYSQL_DB + "?charset=utf8mb4"
|
||||
print("MYSQL_CONN_URL :", MYSQL_CONN_URL)
|
||||
|
||||
__version__ = "2.0.0"
|
||||
# 每次发布时候更新。
|
||||
|
||||
# https://docs.sqlalchemy.org/en/20/errors.html#error-e3q8
|
||||
#
|
||||
def engine():
|
||||
engine = create_engine(MYSQL_CONN_URL, pool_size=10, max_overflow=20)
|
||||
#encoding='utf8', convert_unicode=True)
|
||||
return engine
|
||||
|
||||
def engine_to_db(to_db):
|
||||
MYSQL_CONN_URL_NEW = "mysql+mysqldb://" + MYSQL_USER + ":" + MYSQL_PWD + "@" + MYSQL_HOST + ":" + MYSQL_PORT + "/" + to_db + "?charset=utf8mb4"
|
||||
engine = create_engine(MYSQL_CONN_URL_NEW, pool_size=10, max_overflow=20)
|
||||
#encoding='utf8', convert_unicode=True)
|
||||
return engine
|
||||
|
||||
# 通过数据库链接 engine。
|
||||
def conn():
|
||||
try:
|
||||
db = MySQLdb.connect(MYSQL_HOST, MYSQL_USER, MYSQL_PWD, MYSQL_DB, charset="utf8")
|
||||
# db.autocommit = True
|
||||
except Exception as e:
|
||||
print("conn error :", e)
|
||||
db.autocommit(on=True)
|
||||
return db.cursor()
|
||||
|
||||
|
||||
# 定义通用方法函数,插入数据库表,并创建数据库主键,保证重跑数据的时候索引唯一。
|
||||
def insert_db(data, table_name, write_index, primary_keys):
|
||||
# 插入默认的数据库。
|
||||
insert_other_db(MYSQL_DB, data, table_name, write_index, primary_keys)
|
||||
|
||||
|
||||
# 增加一个插入到其他数据库的方法。
|
||||
def insert_other_db(to_db, data, table_name, write_index, primary_keys):
|
||||
# 定义engine
|
||||
engine_mysql = engine_to_db(to_db)
|
||||
# 使用 http://docs.sqlalchemy.org/en/latest/core/reflection.html
|
||||
# 使用检查检查数据库表是否有主键。
|
||||
insp = inspect(engine_mysql)
|
||||
col_name_list = data.columns.tolist()
|
||||
# 如果有索引,把索引增加到varchar上面。
|
||||
if write_index:
|
||||
# 插入到第一个位置:
|
||||
col_name_list.insert(0, data.index.name)
|
||||
print(col_name_list)
|
||||
data.to_sql(name=table_name, con=engine_mysql, schema=to_db, if_exists='append',
|
||||
dtype={col_name: NVARCHAR(length=255) for col_name in col_name_list}, index=write_index)
|
||||
|
||||
# print(insp.get_pk_constraint(table_name))
|
||||
# print()
|
||||
# print(type(insp))
|
||||
# 判断是否存在主键
|
||||
if insp.get_pk_constraint(table_name)['constrained_columns'] == []:
|
||||
with engine_mysql.connect() as con:
|
||||
# 执行数据库插入数据。
|
||||
try:
|
||||
con.execute('ALTER TABLE `%s` ADD PRIMARY KEY (%s);' % (table_name, primary_keys))
|
||||
except Exception as e:
|
||||
print("################## ADD PRIMARY KEY ERROR :", e)
|
||||
|
||||
|
||||
|
||||
|
||||
# 插入数据。
|
||||
def insert(sql, params=()):
|
||||
with conn() as db:
|
||||
print("insert sql:" + sql)
|
||||
try:
|
||||
db.execute(sql, params)
|
||||
except Exception as e:
|
||||
print("error :", e)
|
||||
|
||||
|
||||
# 查询数据
|
||||
def select(sql, params=()):
|
||||
with conn() as db:
|
||||
print("select sql:" + sql)
|
||||
try:
|
||||
db.execute(sql, params)
|
||||
except Exception as e:
|
||||
print("error :", e)
|
||||
result = db.fetchall()
|
||||
return result
|
||||
|
||||
|
||||
# 计算数量
|
||||
def select_count(sql, params=()):
|
||||
with conn() as db:
|
||||
print("select sql:" + sql)
|
||||
try:
|
||||
db.execute(sql, params)
|
||||
except Exception as e:
|
||||
print("error :", e)
|
||||
result = db.fetchall()
|
||||
# 只有一个数组中的第一个数据
|
||||
if len(result) == 1:
|
||||
return int(result[0][0])
|
||||
else:
|
||||
return 0
|
||||
|
||||
|
||||
# 通用函数。获得日期参数。
|
||||
def run_with_args(run_fun):
|
||||
tmp_datetime_show = datetime.datetime.now() # 修改成默认是当日执行 + datetime.timedelta()
|
||||
tmp_hour_int = int(tmp_datetime_show.strftime("%H"))
|
||||
if tmp_hour_int < 12 :
|
||||
# 判断如果是每天 中午 12 点之前运行,跑昨天的数据。
|
||||
tmp_datetime_show = (tmp_datetime_show + datetime.timedelta(days=-1))
|
||||
tmp_datetime_str = tmp_datetime_show.strftime("%Y-%m-%d %H:%M:%S.%f")
|
||||
print("\n######################### hour_int %d " % tmp_hour_int)
|
||||
str_db = "MYSQL_HOST :" + MYSQL_HOST + ", MYSQL_USER :" + MYSQL_USER + ", MYSQL_DB :" + MYSQL_DB
|
||||
print("\n######################### " + str_db + " ######################### ")
|
||||
print("\n######################### begin run %s %s #########################" % (run_fun, tmp_datetime_str))
|
||||
start = time.time()
|
||||
# 要支持数据重跑机制,将日期传入。循环次数
|
||||
if len(sys.argv) == 3:
|
||||
# python xxx.py 2017-07-01 10
|
||||
tmp_year, tmp_month, tmp_day = sys.argv[1].split("-")
|
||||
loop = int(sys.argv[2])
|
||||
tmp_datetime = datetime.datetime(int(tmp_year), int(tmp_month), int(tmp_day))
|
||||
for i in range(0, loop):
|
||||
# 循环插入多次数据,重复跑历史数据使用。
|
||||
# time.sleep(5)
|
||||
tmp_datetime_new = tmp_datetime + datetime.timedelta(days=i)
|
||||
try:
|
||||
run_fun(tmp_datetime_new)
|
||||
except Exception as e:
|
||||
print("error :", e)
|
||||
traceback.print_exc()
|
||||
elif len(sys.argv) == 2:
|
||||
# python xxx.py 2017-07-01
|
||||
tmp_year, tmp_month, tmp_day = sys.argv[1].split("-")
|
||||
tmp_datetime = datetime.datetime(int(tmp_year), int(tmp_month), int(tmp_day))
|
||||
try:
|
||||
run_fun(tmp_datetime)
|
||||
except Exception as e:
|
||||
print("error :", e)
|
||||
traceback.print_exc()
|
||||
else:
|
||||
# tmp_datetime = datetime.datetime.now() + datetime.timedelta(days=-1)
|
||||
try:
|
||||
run_fun(tmp_datetime_show) # 使用当前时间
|
||||
except Exception as e:
|
||||
print("error :", e)
|
||||
traceback.print_exc()
|
||||
print("######################### finish %s , use time: %s #########################" % (
|
||||
tmp_datetime_str, time.time() - start))
|
||||
|
||||
|
||||
# 设置基础目录,每次加载使用。
|
||||
bash_stock_tmp = "/data/cache/hist_data_cache/%s/%s/"
|
||||
if not os.path.exists(bash_stock_tmp):
|
||||
os.makedirs(bash_stock_tmp) # 创建多个文件夹结构。
|
||||
print("######################### init tmp dir #########################")
|
||||
|
||||
|
||||
# 增加读取股票缓存方法。加快处理速度。
|
||||
def get_hist_data_cache(code, date_start, date_end):
|
||||
cache_dir = bash_stock_tmp % (date_end[0:7], date_end)
|
||||
# 如果没有文件夹创建一个。月文件夹和日文件夹。方便删除。
|
||||
# print("cache_dir:", cache_dir)
|
||||
if not os.path.exists(cache_dir):
|
||||
os.makedirs(cache_dir)
|
||||
cache_file = cache_dir + "%s^%s.gzip.pickle" % (date_end, code)
|
||||
# 如果缓存存在就直接返回缓存数据。压缩方式。
|
||||
if os.path.isfile(cache_file):
|
||||
print("######### read from cache #########", cache_file)
|
||||
return pd.read_pickle(cache_file, compression="gzip")
|
||||
else:
|
||||
# https://akshare.akfamily.xyz/data/index/index.html#id4
|
||||
# 获取历史行情,em
|
||||
#stock = ak.stock_zh_a_hist(symbol= code, start_date=date_start,
|
||||
# end_date=date_end, adjust="")
|
||||
code = gp_type_szsh(code)+ code
|
||||
print("######### get data, write cache #########", code, date_start, date_end)
|
||||
|
||||
stock = ak.stock_zh_index_daily_em(symbol= code,
|
||||
start_date=date_start.replace("-", ""), end_date=date_end.replace("-", ""))
|
||||
print(stock)
|
||||
if stock is None or stock.empty:
|
||||
return None
|
||||
|
||||
stock.columns = ['date', 'open', 'close', 'high', 'low', 'volume', 'amount']
|
||||
# 数据返回的是带 0 列是索引,第一列是 date 日期
|
||||
# date open close high low volume amount
|
||||
# 0 2024-09-20 9.81 9.90 9.90 9.78 797297 7.851212e+08
|
||||
|
||||
stock.set_index('date', inplace=True)
|
||||
#stock = stock.sort_index(0) # 将数据按照日期排序下。
|
||||
print(stock)
|
||||
stock.to_pickle(cache_file, compression="gzip")
|
||||
return stock
|
||||
|
||||
|
||||
# 沪市股票包含上证主板和科创板和B股:沪市主板股票代码是60开头、科创板股票代码是688开头、B股代码900开头。
|
||||
# 深市股票包含主板、中小板、创业板和B股:深市主板股票代码是000开头、中小板股票代码002开头、创业板300开头、B股代码200开头
|
||||
# print(gp_type_szsh('002340'))
|
||||
#
|
||||
def gp_type_szsh(gp):
|
||||
if gp.find('60',0,3)==0:
|
||||
gp_type='sh'
|
||||
elif gp.find('688',0,4)==0:
|
||||
gp_type='sh'
|
||||
elif gp.find('900',0,4)==0:
|
||||
gp_type='sh'
|
||||
elif gp.find('00',0,3)==0:
|
||||
gp_type='sz'
|
||||
elif gp.find('300',0,4)==0:
|
||||
gp_type='sz'
|
||||
elif gp.find('200',0,4)==0:
|
||||
gp_type='sz'
|
||||
return gp_type
|
||||
@@ -0,0 +1,196 @@
|
||||
#!/usr/local/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
class StockWebData:
|
||||
def __init__(self, mode, type, name, table_name, columns, column_names, primary_key, order_by):
|
||||
self.mode = mode # 模式,query,editor 查询和编辑模式
|
||||
self.type = type
|
||||
self.name = name
|
||||
self.table_name = table_name
|
||||
self.columns = columns
|
||||
self.column_names = column_names
|
||||
self.primary_key = primary_key
|
||||
self.order_by = order_by
|
||||
if mode == "query":
|
||||
self.url = "/stock/data?table_name=" + self.table_name
|
||||
elif mode == "editor":
|
||||
self.url = "/data/editor?table_name=" + self.table_name
|
||||
|
||||
|
||||
STOCK_WEB_DATA_LIST = []
|
||||
|
||||
|
||||
# https://www.akshare.xyz/zh_CN/latest/data/stock/stock.html#id1
|
||||
# 限量: 单次返回所有 A 股上市公司的实时行情数据
|
||||
STOCK_WEB_DATA_LIST.append(
|
||||
StockWebData(
|
||||
mode="query",
|
||||
type="1,股票基本数据",
|
||||
name="每日股票数据-东财",
|
||||
table_name="stock_zh_a_spot_em",
|
||||
columns= ['date', 'code', 'name', 'last_price', 'change_percent', 'change_amount',
|
||||
'volume', 'turnover', 'amplitude', 'high', 'low', 'open', 'closed', 'volume_ratio',
|
||||
'turnover_rate', 'pe_ratio','pb_ratio', 'market_cap','circulating_market_cap','rise_speed',
|
||||
'change_5min', 'change_ercent_60day','ytd_change_percent'] ,
|
||||
column_names=['日期','代码','名称','最新价','涨跌幅','涨跌额','成交量','成交额',
|
||||
'振幅','最高','最低','今开','昨收','量比','换手率','动态市盈率',
|
||||
'市净率', '总市值', '流通市值', '涨速', '5分钟涨跌', '60日涨跌幅', '年初至今涨跌幅'],
|
||||
primary_key=[],
|
||||
order_by=" code asc "
|
||||
)
|
||||
)
|
||||
|
||||
STOCK_WEB_DATA_LIST.append(
|
||||
StockWebData(
|
||||
mode="query",
|
||||
type="1,股票基本数据",
|
||||
name="龙虎榜-个股上榜-新浪",
|
||||
table_name="stock_lhb_ggtj_sina",
|
||||
columns= ['date','code','name','ranking_times','sum_buy','sum_sell','net_amount','buy_seat','sell_seat'],
|
||||
column_names=['日期','代码', '名称', '上榜次数', '累积购买额', '累积卖出额', '净额', '买入席位数', '卖出席位数'],
|
||||
primary_key=[],
|
||||
order_by=" code asc "
|
||||
)
|
||||
)
|
||||
|
||||
STOCK_WEB_DATA_LIST.append(
|
||||
StockWebData(
|
||||
mode="query",
|
||||
type="1,股票基本数据",
|
||||
name="数据中心-大宗交易",
|
||||
table_name="stock_dzjy_mrtj",
|
||||
columns= ['date', 'code', 'name', 'quote_change', 'close_price', 'average_price',
|
||||
'overflow_rate', 'trade_number', 'sum_volume', 'sum_turnover',
|
||||
'turnover_market_rate'],
|
||||
column_names=['日期', '代码', '名称', '涨跌幅', '收盘价', '成交均价',
|
||||
'折溢率', '成交笔数', '成交总量', '成交总额',
|
||||
'成交总额/流通市值'],
|
||||
primary_key=[],
|
||||
order_by=" code asc "
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
|
||||
# 每日股票指标lite猜想买入。
|
||||
STOCK_WEB_DATA_LIST.append(
|
||||
StockWebData(
|
||||
mode="query",
|
||||
type="2,每日数据猜想",
|
||||
name="股票指标lite猜想买入",
|
||||
table_name="guess_indicators_lite_buy_daily",
|
||||
# columns=['date', 'code', 'name', 'latest_price', 'quote_change', 'ups_downs', 'volume', 'turnover',
|
||||
# 'amplitude', 'high', 'low', 'open', 'closed', 'volume_ratio', 'turnover_rate', 'pe_dynamic', 'pb',
|
||||
# 'kdjj', 'rsi_6', 'cci'],
|
||||
# column_names=['日期', '代码', '名称', '最新价', '涨跌幅', '涨跌额', '成交量', '成交额',
|
||||
# '振幅', '最高', '最低', '今开', '昨收', '量比', '换手率', '动态市盈率', '市净率',
|
||||
# 'kdjj', 'rsi_6', 'cci'],
|
||||
columns= ['date', 'code', 'name', 'last_price', 'change_percent', 'change_amount',
|
||||
'volume', 'turnover', 'amplitude', 'high', 'low', 'open', 'closed', 'volume_ratio',
|
||||
'turnover_rate', 'pe_ratio','pb_ratio', 'market_cap','circulating_market_cap','rise_speed',
|
||||
'change_5min', 'change_ercent_60day','ytd_change_percent',
|
||||
'boll', 'boll_lb', 'boll_ub', 'kdjd', 'kdjj', 'kdjk', 'macd', 'macdh',
|
||||
'macds', 'pdi','trix', 'trix_9_sma', 'vr', 'vr_6_sma', 'wr_10', 'wr_6'] ,
|
||||
# 中文说明前面和 1 数据一致。
|
||||
column_names=['日期','代码','名称','最新价','涨跌幅','涨跌额','成交量','成交额',
|
||||
'振幅','最高','最低','今开','昨收','量比','换手率','动态市盈率',
|
||||
'市净率', '总市值', '流通市值', '涨速', '5分钟涨跌', '60日涨跌幅',
|
||||
'年初至今涨跌幅',
|
||||
'boll', 'boll_lb', 'boll_ub',
|
||||
'kdjd', 'kdjj', 'kdjk', 'macd', 'macdh', 'macds', 'pdi',
|
||||
'trix', 'trix_9_sma', 'vr', 'vr_6_sma', 'wr_10', 'wr_6'],
|
||||
primary_key=[],
|
||||
order_by=" buy_date desc "
|
||||
)
|
||||
)
|
||||
|
||||
# 每日股票指标lite猜想卖出。
|
||||
STOCK_WEB_DATA_LIST.append(
|
||||
StockWebData(
|
||||
mode="query",
|
||||
type="2,每日数据猜想",
|
||||
name="股票指标lite猜想卖出",
|
||||
table_name="guess_indicators_lite_sell_daily",
|
||||
# columns=['date', 'code', 'name', 'latest_price', 'quote_change', 'ups_downs', 'volume', 'turnover',
|
||||
# 'amplitude', 'high', 'low', 'open', 'closed', 'volume_ratio', 'turnover_rate', 'pe_dynamic', 'pb',
|
||||
# 'kdjj', 'rsi_6', 'cci'],
|
||||
# column_names=['日期', '代码', '名称', '最新价', '涨跌幅', '涨跌额', '成交量', '成交额',
|
||||
# '振幅', '最高', '最低', '今开', '昨收', '量比', '换手率', '动态市盈率', '市净率',
|
||||
# 'kdjj', 'rsi_6', 'cci'],
|
||||
columns= ['date', 'code', 'name', 'last_price', 'change_percent', 'change_amount',
|
||||
'volume', 'turnover', 'amplitude', 'high', 'low', 'open', 'closed', 'volume_ratio',
|
||||
'turnover_rate', 'pe_ratio','pb_ratio', 'market_cap','circulating_market_cap','rise_speed',
|
||||
'change_5min', 'change_ercent_60day','ytd_change_percent',
|
||||
'boll', 'boll_lb', 'boll_ub', 'kdjd', 'kdjj', 'kdjk', 'macd', 'macdh',
|
||||
'macds', 'pdi','trix', 'trix_9_sma', 'vr', 'vr_6_sma', 'wr_10', 'wr_6'] ,
|
||||
# 中文说明前面和 1 数据一致。
|
||||
column_names=['日期','代码','名称','最新价','涨跌幅','涨跌额','成交量','成交额',
|
||||
'振幅','最高','最低','今开','昨收','量比','换手率','动态市盈率',
|
||||
'市净率', '总市值', '流通市值', '涨速', '5分钟涨跌', '60日涨跌幅',
|
||||
'年初至今涨跌幅',
|
||||
'boll', 'boll_lb', 'boll_ub',
|
||||
'kdjd', 'kdjj', 'kdjk', 'macd', 'macdh', 'macds', 'pdi',
|
||||
'trix', 'trix_9_sma', 'vr', 'vr_6_sma', 'wr_10', 'wr_6'],
|
||||
primary_key=[],
|
||||
order_by=" buy_date desc "
|
||||
)
|
||||
)
|
||||
|
||||
# 每日股票指标lite猜想。
|
||||
STOCK_WEB_DATA_LIST.append(
|
||||
StockWebData(
|
||||
mode="query",
|
||||
type="2,每日数据猜想",
|
||||
name="股票指标猜想原始数据",
|
||||
table_name="guess_indicators_daily",
|
||||
|
||||
columns= ['date', 'code', 'name', 'last_price', 'change_percent', 'change_amount',
|
||||
'volume', 'turnover', 'amplitude', 'high', 'low', 'open', 'closed', 'volume_ratio',
|
||||
'turnover_rate', 'pe_ratio','pb_ratio', 'market_cap','circulating_market_cap','rise_speed',
|
||||
'change_5min', 'change_ercent_60day','ytd_change_percent',
|
||||
'boll', 'boll_lb', 'boll_ub', 'kdjd', 'kdjj', 'kdjk', 'macd', 'macdh',
|
||||
'macds', 'pdi','trix', 'trix_9_sma', 'vr', 'vr_6_sma', 'wr_10', 'wr_6'] ,
|
||||
# 中文说明前面和 1 数据一致。
|
||||
column_names=['日期','代码','名称','最新价','涨跌幅','涨跌额','成交量','成交额',
|
||||
'振幅','最高','最低','今开','昨收','量比','换手率','动态市盈率',
|
||||
'市净率', '总市值', '流通市值', '涨速', '5分钟涨跌', '60日涨跌幅',
|
||||
'年初至今涨跌幅',
|
||||
'boll', 'boll_lb', 'boll_ub',
|
||||
'kdjd', 'kdjj', 'kdjk', 'macd', 'macdh', 'macds', 'pdi',
|
||||
'trix', 'trix_9_sma', 'vr', 'vr_6_sma', 'wr_10', 'wr_6'],
|
||||
|
||||
# columns=['date','code','name','latest_price','quote_change','ups_downs',
|
||||
# 'adx', 'adxr', 'boll', 'boll_lb', 'boll_ub', 'cci', 'cci_20', 'close_-1_r',
|
||||
# 'close_-2_r', 'code', 'cr', 'cr-ma1', 'cr-ma2', 'cr-ma3', 'date', 'dma', 'dx',
|
||||
# 'kdjd', 'kdjj', 'kdjk', 'macd', 'macdh', 'macds', 'mdi', 'pdi',
|
||||
# 'rsi_12', 'rsi_6', 'trix', 'trix_9_sma', 'vr', 'vr_6_sma', 'wr_10', 'wr_6'],
|
||||
# column_names=['日期','代码','名称','最新价','涨跌幅','涨跌额',
|
||||
# 'adx', 'adxr', 'boll', 'boll_lb', 'boll_ub', 'cci', 'cci_20', 'close_-1_r',
|
||||
# 'close_-2_r', 'code', 'cr', 'cr-ma1', 'cr-ma2', 'cr-ma3', 'date', 'dma', 'dx',
|
||||
# 'kdjd', 'kdjj', 'kdjk', 'macd', 'macdh', 'macds', 'mdi', 'pdi',
|
||||
# 'rsi_12', 'rsi_6', 'trix', 'trix_9_sma', 'vr', 'vr_6_sma', 'wr_10', 'wr_6'],
|
||||
|
||||
primary_key=[],
|
||||
order_by=' date desc '
|
||||
)
|
||||
)
|
||||
|
||||
# "code", "name: pchange", "amount", "buy", "bratio", "sell", "sratio", "reason", "date"
|
||||
# 代码 名称 当日涨跌幅 龙虎榜成交额(万) 买入额(万) 买入占总成交比例 卖出额(万) 卖出占总成交比例 上榜原因 日期
|
||||
|
||||
|
||||
STOCK_WEB_DATA_MAP = {}
|
||||
WEB_EASTMONEY_URL = "http://quote.eastmoney.com/%s.html"
|
||||
# 再拼接成Map使用。
|
||||
for tmp in STOCK_WEB_DATA_LIST:
|
||||
# try:
|
||||
# # 增加columns 字段中的【查看股票】
|
||||
# tmp_idx = tmp.columns.index("code")
|
||||
# tmp.column_names.insert(tmp_idx + 1, "查看股票")
|
||||
# except Exception as e:
|
||||
# print("error :", e)
|
||||
|
||||
STOCK_WEB_DATA_MAP[tmp.table_name] = tmp
|
||||
|
||||
if len(tmp.columns) != len(tmp.column_names):
|
||||
print(u"error:", tmp.table_name, ",columns:", len(tmp.columns), ",column_names:", len(tmp.column_names))
|
||||
@@ -0,0 +1,358 @@
|
||||
#!/usr/local/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
class StockWebData:
|
||||
def __init__(self, mode, type, name, table_name, columns, column_names, primary_key, order_by):
|
||||
self.mode = mode # 模式,query,editor 查询和编辑模式
|
||||
self.type = type
|
||||
self.name = name
|
||||
self.table_name = table_name
|
||||
self.columns = columns
|
||||
self.column_names = column_names
|
||||
self.primary_key = primary_key
|
||||
self.order_by = order_by
|
||||
if mode == "query":
|
||||
self.url = "/stock/data?table_name=" + self.table_name
|
||||
elif mode == "editor":
|
||||
self.url = "/data/editor?table_name=" + self.table_name
|
||||
|
||||
|
||||
STOCK_WEB_DATA_LIST = []
|
||||
|
||||
STOCK_WEB_DATA_LIST.append(
|
||||
StockWebData(
|
||||
mode="query",
|
||||
type="宏观经济数据",
|
||||
name="存款利率",
|
||||
table_name="ts_deposit_rate",
|
||||
columns=["date", "deposit_type", "rate"],
|
||||
column_names=["日期", "存款类型", "存款利率"],
|
||||
primary_key=[],
|
||||
order_by=" date desc "
|
||||
)
|
||||
)
|
||||
|
||||
STOCK_WEB_DATA_LIST.append(
|
||||
StockWebData(
|
||||
mode="query",
|
||||
type="宏观经济数据",
|
||||
name="贷款利率",
|
||||
table_name="ts_loan_rate",
|
||||
columns=["date", "loan_type", "rate"],
|
||||
column_names=["日期", "贷款类型", "存款利率"],
|
||||
primary_key=[],
|
||||
order_by=" date desc "
|
||||
)
|
||||
)
|
||||
|
||||
STOCK_WEB_DATA_LIST.append(
|
||||
StockWebData(
|
||||
mode="query",
|
||||
type="宏观经济数据",
|
||||
name="存款准备金率",
|
||||
table_name="ts_rrr",
|
||||
columns=["date", "before", "now", "changed"],
|
||||
column_names=["变动日期", "调整前存款准备金率(%)", "调整后存款准备金率(%)", "调整幅度(%)"],
|
||||
primary_key=[],
|
||||
order_by=" date desc "
|
||||
)
|
||||
)
|
||||
|
||||
STOCK_WEB_DATA_LIST.append(
|
||||
StockWebData(
|
||||
mode="query",
|
||||
type="宏观经济数据",
|
||||
name="货币供应量",
|
||||
table_name="ts_money_supply",
|
||||
columns=["month", "m2", "m2_yoy", "m1", "m1_yoy", "m0", "m0_yoy", "cd", "cd_yoy", "qm", "qm_yoy", "ftd",
|
||||
"ftd_yoy", "sd", "sd_yoy", "rests", "rests_yoy"],
|
||||
column_names=["统计时间", "货币和准货币(广义货币M2)(亿元)", "货币和准货币(广义货币M2)同比增长(%)",
|
||||
"货币(狭义货币M1)(亿元)", "货币(狭义货币M1)同比增长(%)",
|
||||
"流通中现金(M0)(亿元)", "流通中现金(M0)同比增长(%)",
|
||||
"活期存款(亿元)", "活期存款同比增长(%)",
|
||||
"准货币(亿元)", "准货币同比增长(%)",
|
||||
"定期存款(亿元)", "定期存款同比增长(%)",
|
||||
"储蓄存款(亿元)", "储蓄存款同比增长(%)",
|
||||
"其他存款(亿元)", "其他存款同比增长(%)"
|
||||
],
|
||||
primary_key=[],
|
||||
order_by=" month desc "
|
||||
)
|
||||
)
|
||||
|
||||
# http://tushare.org/fundamental.html
|
||||
# 参考官网网站的文档,是最全的。
|
||||
STOCK_WEB_DATA_LIST.append(
|
||||
StockWebData(
|
||||
mode="query",
|
||||
type="基本面数据",
|
||||
name="股票列表",
|
||||
table_name="ts_stock_basics",
|
||||
columns=["code", "name", "industry", "area", "pe", "outstanding", "totals", "totalAssets", "liquidAssets",
|
||||
"fixedAssets", "reserved", "reservedPerShare", "esp", "bvps", "pb", "timeToMarket",
|
||||
"undp", "perundp", "rev", "profit", "gpr", "npr", "holders"],
|
||||
column_names=["代码", "名称", "所属行业", "地区", "市盈率", "流通股本(亿)", "总股本(亿)", "总资产(万)", "流动资产",
|
||||
"固定资产", "公积金", "每股公积金", "每股收益", "每股净资", "市净率", "上市日期", "未分利润",
|
||||
"每股未分配", "收入同比(%)", "利润同比(%)", "毛利率(%)", "净利润率(%)", "股东人数"
|
||||
],
|
||||
primary_key=[],
|
||||
order_by=" code asc "
|
||||
)
|
||||
)
|
||||
|
||||
# 业绩报告(主表)
|
||||
STOCK_WEB_DATA_LIST.append(
|
||||
StockWebData(
|
||||
mode="query",
|
||||
type="基本面数据",
|
||||
name="业绩报告(主表)",
|
||||
table_name="ts_report_data",
|
||||
columns=["quarter", "code", "name", "eps", "eps_yoy", "bvps", "roe", "epcf", "net_profits",
|
||||
"profits_yoy", "distrib", "report_date"],
|
||||
column_names=["季度", "代码", "名称", "每股收益", "每股收益同比(%)", "每股净资产", "净资产收益率(%)", "每股现金流量(元)", ",净利润(万元)",
|
||||
"净利润同比(%)", "分配方案", "发布日期"
|
||||
],
|
||||
primary_key=[],
|
||||
order_by=" quarter desc "
|
||||
)
|
||||
)
|
||||
|
||||
# 盈利能力
|
||||
STOCK_WEB_DATA_LIST.append(
|
||||
StockWebData(
|
||||
mode="query",
|
||||
type="基本面数据",
|
||||
name="盈利能力",
|
||||
table_name="ts_profit_data",
|
||||
columns=["quarter", "code", "name", "roe", "net_profit_ratio", "gross_profit_rate",
|
||||
"net_profits", "eps", "business_income", "bips"],
|
||||
column_names=["季度", "代码", "名称", "净资产收益率(%)", "净利率(%)", "毛利率(%)", "净利润(万元)",
|
||||
"每股收益", "营业收入(百万元)", "每股主营业务收入(元)"],
|
||||
primary_key=[],
|
||||
order_by=" quarter desc "
|
||||
)
|
||||
)
|
||||
|
||||
STOCK_WEB_DATA_LIST.append(
|
||||
StockWebData(
|
||||
mode="query",
|
||||
type="基本面数据",
|
||||
name="营运能力",
|
||||
table_name="ts_operation_data",
|
||||
columns=["quarter", "code", "name", "arturnover", "arturndays",
|
||||
"inventory_turnover", "inventory_days", "currentasset_turnover", "currentasset_days"],
|
||||
column_names=["季度", "代码", "名称", "应收账款周转率(次)", "应收账款周转天数(天)", "存货周转率(次)", "存货周转天数(天)",
|
||||
"流动资产周转率(次)", "流动资产周转天数(天)"
|
||||
],
|
||||
primary_key=[],
|
||||
order_by=" quarter desc "
|
||||
)
|
||||
)
|
||||
|
||||
STOCK_WEB_DATA_LIST.append(
|
||||
StockWebData(
|
||||
mode="query",
|
||||
type="基本面数据",
|
||||
name="成长能力",
|
||||
table_name="ts_growth_data",
|
||||
columns=["quarter", "code", "name", "mbrg", "nprg", "nav", "targ", "epsg", "seg"],
|
||||
column_names=["季度", "代码", "名称", "主营业务收入增长率(%)", "净利润增长率(%)", "净资产增长率", "总资产增长率",
|
||||
"每股收益增长率", "股东权益增长率"],
|
||||
primary_key=[],
|
||||
order_by=" quarter desc "
|
||||
)
|
||||
)
|
||||
|
||||
# "code", "name: pchange", "amount", "buy", "bratio", "sell", "sratio", "reason", "date"
|
||||
# 代码 名称 当日涨跌幅 龙虎榜成交额(万) 买入额(万) 买入占总成交比例 卖出额(万) 卖出占总成交比例 上榜原因 日期
|
||||
|
||||
|
||||
STOCK_WEB_DATA_LIST.append(
|
||||
StockWebData(
|
||||
mode="query",
|
||||
type="每日数据",
|
||||
name="龙虎榜",
|
||||
table_name="ts_top_list",
|
||||
columns=["date", "code", "name", "pchange", "amount", "buy", "bratio", "sell", "sratio", "reason"],
|
||||
column_names=["日期", "代码", "名称", "当日涨跌幅", "龙虎榜成交额(万)", "买入额(万)", "买入占总成交比例", "卖出额(万)",
|
||||
"卖出占总成交比例", "上榜原因"],
|
||||
primary_key=[],
|
||||
order_by=" date desc "
|
||||
)
|
||||
)
|
||||
# 实时行情
|
||||
STOCK_WEB_DATA_LIST.append(
|
||||
StockWebData(
|
||||
mode="query",
|
||||
type="每日数据",
|
||||
name="每日股票数据",
|
||||
table_name="ts_today_all",
|
||||
columns=["date", "code", "name", "changepercent", "trade", "open", "high", "low", "settlement", "volume",
|
||||
"turnoverratio", "amount", "per", "pb", "mktcap", "nmc"],
|
||||
column_names=["日期", "代码", "名称", "涨跌幅", "现价", "开盘价", "最高价", "最低价", "昨日收盘价", "成交量",
|
||||
"换手率", "成交金额", "市盈率", "市净率", "总市值", "流通市值"],
|
||||
primary_key=[],
|
||||
order_by=" date desc "
|
||||
)
|
||||
)
|
||||
# 大盘指数行情列表
|
||||
STOCK_WEB_DATA_LIST.append(
|
||||
StockWebData(
|
||||
mode="query",
|
||||
type="每日数据",
|
||||
name="每日大盘指数行情",
|
||||
table_name="ts_index_all",
|
||||
columns=["date", "code", "name", "change", "open", "preclose", "close", "high", "low", "volume", "amount"],
|
||||
column_names=["日期", "代码", "名称", "涨跌幅", "开盘点位", "昨日收盘点位", "收盘点位", "最高点位", "最低点位", "成交量(手)", "成交金额(亿元)"],
|
||||
primary_key=[],
|
||||
order_by=" date desc "
|
||||
)
|
||||
)
|
||||
|
||||
# 每日波峰波谷猜想
|
||||
STOCK_WEB_DATA_LIST.append(
|
||||
StockWebData(
|
||||
mode="query",
|
||||
type="每日数据猜想",
|
||||
name="每日波峰波谷猜想",
|
||||
table_name="guess_period_daily",
|
||||
columns=["date", "code", "name", "wave_base", "wave_crest", "wave_mean", "up_rate",
|
||||
"changepercent", "trade", "open", "high", "low", "settlement", "volume",
|
||||
"turnoverratio", "amount", "per", "pb", "mktcap", "nmc"],
|
||||
column_names=["日期", "代码", "名称", "5波峰平均", "5波谷平均", "价格平均", "上涨率猜想%",
|
||||
"涨跌幅", "现价", "开盘价", "最高价", "最低价", "昨日收盘价", "成交量",
|
||||
"换手率", "成交金额", "市盈率", "市净率", "总市值", "流通市值"],
|
||||
primary_key=[],
|
||||
order_by=" date desc "
|
||||
)
|
||||
)
|
||||
|
||||
# 每日收益率猜想。
|
||||
STOCK_WEB_DATA_LIST.append(
|
||||
StockWebData(
|
||||
mode="query",
|
||||
type="每日数据猜想",
|
||||
name="每日收益率猜想",
|
||||
table_name="guess_return_daily",
|
||||
columns=["date", "code", "name",
|
||||
"5d", "10d", "20d", "60d", "5-10d", "5-20d", "mov_vol", "return",
|
||||
"changepercent", "trade", "open", "high", "low", "settlement", "volume",
|
||||
"turnoverratio", "amount", "per", "pb", "mktcap", "nmc"],
|
||||
column_names=["日期", "代码", "名称",
|
||||
"5周线", "10半月线", "20月线", "60季度线", "5-10日差%", "5-20日差%", "收益", "收益率移动标准差",
|
||||
"涨跌幅", "现价", "开盘价", "最高价", "最低价", "昨日收盘价", "成交量",
|
||||
"换手率", "成交金额", "市盈率", "市净率", "总市值", "流通市值"],
|
||||
primary_key=[],
|
||||
order_by=" date desc "
|
||||
)
|
||||
)
|
||||
|
||||
# 每日股票指标lite猜想。
|
||||
STOCK_WEB_DATA_LIST.append(
|
||||
StockWebData(
|
||||
mode="query",
|
||||
type="每日数据猜想",
|
||||
name="每日股票指标lite猜想",
|
||||
table_name="guess_indicators_lite_daily",
|
||||
columns=["date", "code", "name", "changepercent", "trade", "open", "high", "low", "settlement", "volume",
|
||||
"turnoverratio", "amount", "per", "pb", "mktcap", "nmc",
|
||||
"kdjj", "rsi_6", "cci"],
|
||||
column_names=["日期", "代码", "名称",
|
||||
"涨跌幅", "现价", "开盘价", "最高价", "最低价", "昨日收盘价", "成交量",
|
||||
"换手率", "成交金额", "市盈率", "市净率", "总市值", "流通市值",
|
||||
"kdjj", "rsi_6", "cci"],
|
||||
primary_key=[],
|
||||
order_by=" date desc "
|
||||
)
|
||||
)
|
||||
|
||||
# 每日股票指标lite猜想买入。
|
||||
STOCK_WEB_DATA_LIST.append(
|
||||
StockWebData(
|
||||
mode="query",
|
||||
type="每日数据猜想",
|
||||
name="每日股票指标lite猜想买入",
|
||||
table_name="guess_indicators_lite_buy_daily",
|
||||
columns=["buy_date", "code", "name", "changepercent", "trade", "turnoverratio", "pb",
|
||||
"kdjj", "rsi_6", "cci", "wave_base", "wave_crest", "wave_mean", "up_rate", "buy", "sell",
|
||||
"today_trade", "income"],
|
||||
column_names=["购买日期", "代码", "名称", "涨跌幅", "现价", "换手率%", "市净率%",
|
||||
"买入kdjj", "买入rsi_6", "买入cci", "波谷", "波峰", "波平均", "上涨率%", "买入", "卖出", "今日价格", "收益"],
|
||||
primary_key=[],
|
||||
order_by=" buy_date desc "
|
||||
)
|
||||
)
|
||||
|
||||
# 每日股票指标lite猜想卖出。
|
||||
STOCK_WEB_DATA_LIST.append(
|
||||
StockWebData(
|
||||
mode="query",
|
||||
type="每日数据猜想",
|
||||
name="每日股票指标lite猜想卖出",
|
||||
table_name="guess_indicators_lite_sell_daily",
|
||||
columns=["date", "buy_date", "code", "name", "changepercent", "trade", "turnoverratio", "pb",
|
||||
"kdjj", "rsi_6", "cci", "wave_base", "wave_crest", "wave_mean", "up_rate", "buy", "sell",
|
||||
"today_trade", "income", "sell_cci", "sell_kdjj", "sell_rsi_6"],
|
||||
column_names=["日期", "购买日期", "代码", "名称", "涨跌幅", "现价", "换手率%", "市净率%",
|
||||
"买入kdjj", "买入rsi_6", "买入cci", "波谷", "波峰", "波平均", "上涨率%", "买入", "卖出", "今日价格", "收益",
|
||||
"卖出kdjj", "卖出rsi_6", "卖出cci", ],
|
||||
primary_key=[],
|
||||
order_by=" buy_date desc "
|
||||
)
|
||||
)
|
||||
|
||||
# 每日股票指标猜想。
|
||||
STOCK_WEB_DATA_LIST.append(
|
||||
StockWebData(
|
||||
mode="query",
|
||||
type="每日数据猜想",
|
||||
name="每日股票指标All猜想",
|
||||
table_name="guess_indicators_daily",
|
||||
columns=["date", "code", "name", "changepercent", "trade", "open", "high", "low", "settlement", "volume",
|
||||
"turnoverratio", "amount", "per", "pb", "mktcap", "nmc",
|
||||
'adx', 'adxr', 'boll', 'boll_lb', 'boll_ub', 'cci', 'cci_20', 'close_-1_r',
|
||||
'close_-2_r', 'code', 'cr', 'cr-ma1', 'cr-ma2', 'cr-ma3', 'date', 'dma', 'dx',
|
||||
'kdjd', 'kdjj', 'kdjk', 'macd', 'macdh', 'macds', 'mdi', 'pdi',
|
||||
'rsi_12', 'rsi_6', 'trix', 'trix_9_sma', 'vr', 'vr_6_sma', 'wr_10', 'wr_6'],
|
||||
column_names=["日期", "代码", "名称",
|
||||
"涨跌幅", "现价", "开盘价", "最高价", "最低价", "昨日收盘价", "成交量",
|
||||
"换手率", "成交金额", "市盈率", "市净率", "总市值", "流通市值",
|
||||
'adx', 'adxr', 'boll', 'boll_lb', 'boll_ub', 'cci', 'cci_20', 'close_-1_r',
|
||||
'close_-2_r', 'code', 'cr', 'cr-ma1', 'cr-ma2', 'cr-ma3', 'date', 'dma', 'dx',
|
||||
'kdjd', 'kdjj', 'kdjk', 'macd', 'macdh', 'macds', 'mdi', 'pdi',
|
||||
'rsi_12', 'rsi_6', 'trix', 'trix_9_sma', 'vr', 'vr_6_sma', 'wr_10', 'wr_6'],
|
||||
primary_key=[],
|
||||
order_by=" date desc "
|
||||
)
|
||||
)
|
||||
|
||||
STOCK_WEB_DATA_LIST.append(
|
||||
StockWebData(
|
||||
mode="query",
|
||||
type="每日数据Keras猜想",
|
||||
name="每日股票数据Keras猜想",
|
||||
table_name="guess_sklearn_ma_daily",
|
||||
columns=["date", "code", "name", "changepercent", "trade", "open", "high", "low", "settlement", "volume",
|
||||
"turnoverratio", "next_close", "sklearn_score", "up_rate"],
|
||||
column_names=["日期", "代码", "名称", "涨跌幅", "现价", "开盘价", "最高价", "最低价", "昨日收盘价", "成交量",
|
||||
"换手率", "预测收盘价", "sk概率", "预测上涨率"],
|
||||
primary_key=[],
|
||||
order_by=" date desc "
|
||||
)
|
||||
)
|
||||
|
||||
STOCK_WEB_DATA_MAP = {}
|
||||
WEB_EASTMONEY_URL = "http://quote.eastmoney.com/%s.html"
|
||||
# 再拼接成Map使用。
|
||||
for tmp in STOCK_WEB_DATA_LIST:
|
||||
try:
|
||||
# 增加columns 字段中的【东方财富】
|
||||
tmp_idx = tmp.columns.index("code")
|
||||
tmp.column_names.insert(tmp_idx + 1, "东方财富")
|
||||
except Exception as e:
|
||||
print("error :", e)
|
||||
|
||||
STOCK_WEB_DATA_MAP[tmp.table_name] = tmp
|
||||
|
||||
if len(tmp.columns) != len(tmp.column_names):
|
||||
print(u"error:", tmp.table_name, ",columns:", len(tmp.columns), ",column_names:", len(tmp.column_names))
|
||||
@@ -0,0 +1,4 @@
|
||||
## 说明
|
||||
|
||||
|
||||
之前测试使用的脚本。执行了一段时间,只是用来进行练习使用的。
|
||||
@@ -0,0 +1,126 @@
|
||||
#!/usr/local/bin/python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
|
||||
import libs.common as common
|
||||
import pandas as pd
|
||||
import numpy as np
|
||||
import math
|
||||
import datetime
|
||||
import heapq
|
||||
|
||||
|
||||
### 对每日指标数据,进行筛选。将符合条件的。二次筛选出来。
|
||||
def stat_all_lite(tmp_datetime):
|
||||
# 要操作的数据库表名称。
|
||||
table_name = "guess_indicators_lite_buy_daily"
|
||||
datetime_str = (tmp_datetime).strftime("%Y-%m-%d")
|
||||
datetime_int = (tmp_datetime).strftime("%Y%m%d")
|
||||
print("datetime_str:", datetime_str)
|
||||
print("datetime_int:", datetime_int)
|
||||
|
||||
# try:
|
||||
# # 删除老数据。guess_indicators_lite_buy_daily 是一张单表,没有日期字段。
|
||||
# del_sql = " DELETE FROM `stock_data`.`%s` WHERE `date`= '%s' " % (table_name, datetime_int)
|
||||
# print("del_sql:", del_sql)
|
||||
# common.insert(del_sql)
|
||||
# print("del_sql")
|
||||
# except Exception as e:
|
||||
# print("error :", e)
|
||||
|
||||
sql_1 = """
|
||||
SELECT `date`, `code`, `name`, `changepercent`, `trade`,`turnoverratio`, `pb` ,`kdjj`,`rsi_6`,`cci`
|
||||
FROM stock_data.guess_indicators_lite_daily WHERE `date` = %s
|
||||
and `changepercent` > 2 and `pb` > 0
|
||||
"""
|
||||
# and `changepercent` > 2 and `pb` > 0 and `turnoverratio` > 5 去除掉换手率参数。
|
||||
data = pd.read_sql(sql=sql_1, con=common.engine(), params=[datetime_int])
|
||||
data = data.drop_duplicates(subset="code", keep="last")
|
||||
print("######## len data ########:", len(data))
|
||||
# del data["name"]
|
||||
# print(data)
|
||||
data["trade_float32"] = data["trade"].astype('float32', copy=True)
|
||||
# 输入 date 用作历史数据查询。
|
||||
stock_merge = pd.DataFrame({
|
||||
"date": data["date"], "code": data["code"], "wave_mean": data["trade"],
|
||||
"wave_crest": data["trade"], "wave_base": data["trade"]}, index=data.index.values)
|
||||
print(stock_merge.head(1))
|
||||
|
||||
stock_merge = stock_merge.apply(apply_merge, axis=1) # , axis=1)
|
||||
del stock_merge["date"] # 合并前删除 date 字段。
|
||||
# 合并数据
|
||||
data_new = pd.merge(data, stock_merge, on=['code'], how='left')
|
||||
|
||||
# 使用 trade_float32 参加计算。
|
||||
data_new = data_new[data_new["trade_float32"] > data_new["wave_base"]] # 交易价格大于波谷价格。
|
||||
data_new = data_new[data_new["trade_float32"] < data_new["wave_crest"]] # 小于波峰价格
|
||||
|
||||
# wave_base wave_crest wave_mean
|
||||
data_new["wave_base"] = data_new["wave_base"].round(2) # 数据保留2位小数
|
||||
data_new["wave_crest"] = data_new["wave_crest"].round(2) # 数据保留2位小数
|
||||
data_new["wave_mean"] = data_new["wave_mean"].round(2) # 数据保留2位小数
|
||||
|
||||
data_new["up_rate"] = (data_new["wave_mean"].sub(data_new["trade_float32"])).div(data_new["wave_crest"]).mul(100)
|
||||
data_new["up_rate"] = data_new["up_rate"].round(2) # 数据保留2位小数
|
||||
|
||||
data_new["buy"] = 1
|
||||
data_new["sell"] = 0
|
||||
data_new["today_trade"] = data_new["trade"]
|
||||
data_new["income"] = 0
|
||||
# 重命名 date
|
||||
data_new.columns.values[0] = "buy_date"
|
||||
del data_new["trade_float32"]
|
||||
|
||||
try:
|
||||
common.insert_db(data_new, table_name, False, "`code`")
|
||||
print("insert_db")
|
||||
except Exception as e:
|
||||
print("error :", e)
|
||||
# 重命名
|
||||
del data_new["name"]
|
||||
print(data_new)
|
||||
|
||||
|
||||
def apply_merge(tmp):
|
||||
date = tmp["date"]
|
||||
code = tmp["code"]
|
||||
date_end = datetime.datetime.strptime(date, "%Y%m%d")
|
||||
date_start = (date_end + datetime.timedelta(days=-300)).strftime("%Y-%m-%d")
|
||||
date_end = date_end.strftime("%Y-%m-%d")
|
||||
print(code, date_start, date_end)
|
||||
|
||||
# open, high, close, low, volume, price_change, p_change, ma5, ma10, ma20, v_ma5, v_ma10, v_ma20, turnover
|
||||
# 使用缓存方法。加快计算速度。
|
||||
stock = common.get_hist_data_cache(code, date_start, date_end)
|
||||
# 增加空判断,如果是空返回 0 数据。
|
||||
if stock is None:
|
||||
return list([code, date, 0, 0, 0])
|
||||
|
||||
stock = pd.DataFrame({"close": stock["close"]}, index=stock.index.values)
|
||||
stock = stock.sort_index(0) # 将数据按照日期排序下。
|
||||
|
||||
# print(stock.head(10))
|
||||
arr = pd.Series(stock["close"].values)
|
||||
# print(df_arr)
|
||||
wave_mean = arr.mean()
|
||||
max_point = 3 # 获得最高的几个采样点。
|
||||
# 计算股票的波峰值。
|
||||
wave_crest = heapq.nlargest(max_point, enumerate(arr), key=lambda x: x[1])
|
||||
wave_crest_mean = pd.DataFrame(wave_crest).mean()
|
||||
|
||||
# 输出元祖第一个元素是index,第二元素是比较的数值 计算数据的波谷值
|
||||
wave_base = heapq.nsmallest(max_point, enumerate(arr), key=lambda x: x[1])
|
||||
wave_base_mean = pd.DataFrame(wave_base).mean()
|
||||
# 输出数据
|
||||
print("##############", len(stock))
|
||||
if len(stock) > 180:
|
||||
# code date wave_base wave_crest wave_mean 顺序必须一致。返回的是行数据,然后填充。
|
||||
return list([code, date, wave_base_mean[1], wave_crest_mean[1], wave_mean])
|
||||
else:
|
||||
return list([code, date, 0, 0, 0])
|
||||
|
||||
|
||||
# main函数入口
|
||||
if __name__ == '__main__':
|
||||
# 二次筛选数据。
|
||||
tmp_datetime = common.run_with_args(stat_all_lite)
|
||||
@@ -0,0 +1,137 @@
|
||||
#!/usr/local/bin/python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
|
||||
import libs.common as common
|
||||
import pandas as pd
|
||||
import numpy as np
|
||||
import math
|
||||
import datetime
|
||||
import heapq
|
||||
import stockstats
|
||||
|
||||
|
||||
# code date today_trade
|
||||
def apply_merge(tmp):
|
||||
date = tmp["date"]
|
||||
code = tmp["code"]
|
||||
date_end = datetime.datetime.strptime(date, "%Y%m%d")
|
||||
date_start = (date_end + datetime.timedelta(days=-300)).strftime("%Y-%m-%d")
|
||||
date_end = date_end.strftime("%Y-%m-%d")
|
||||
print(code, date_start, date_end)
|
||||
|
||||
# open, high, close, low, volume, price_change, p_change, ma5, ma10, ma20, v_ma5, v_ma10, v_ma20, turnover
|
||||
# 使用缓存方法。加快计算速度。
|
||||
stock = common.get_hist_data_cache(code, date_start, date_end)
|
||||
# 增加空判断,如果是空返回 0 数据。
|
||||
if stock is None:
|
||||
return list([code, date, 0.0])
|
||||
print("########")
|
||||
# print(stock.tail(1))
|
||||
close = stock.tail(1)["close"].values[0]
|
||||
print("close: ", close)
|
||||
print("########")
|
||||
return list([code, date, close])
|
||||
|
||||
|
||||
# buy code date sell sell_cci sell_kdjj sell_rsi_6
|
||||
def apply_merge_sell(tmp):
|
||||
date = tmp["date"]
|
||||
code = tmp["code"]
|
||||
date_end = datetime.datetime.strptime(date, "%Y%m%d")
|
||||
date_start = (date_end + datetime.timedelta(days=-300)).strftime("%Y-%m-%d")
|
||||
date_end = date_end.strftime("%Y-%m-%d")
|
||||
print(code, date_start, date_end)
|
||||
|
||||
# open, high, close, low, volume, price_change, p_change, ma5, ma10, ma20, v_ma5, v_ma10, v_ma20, turnover
|
||||
# 使用缓存方法。加快计算速度。
|
||||
stock = common.get_hist_data_cache(code, date_start, date_end)
|
||||
# 增加空判断,如果是空返回 0 数据。
|
||||
if stock is None:
|
||||
return list([1, code, date, 0, 0, 0, 0])
|
||||
print("########")
|
||||
# J大于100时为超买,小于10时为超卖。
|
||||
# 强弱指标保持高于50表示为强势市场,反之低于50表示为弱势市场。
|
||||
# 1、当CCI指标从下向上突破﹢100线而进入非常态区间时,表明股价脱离常态而进入异常波动阶段,
|
||||
# 2、当CCI指标从上向下突破﹣100线而进入另一个非常态区间时,表明股价的盘整阶段已经结束,
|
||||
stockStat = stockstats.StockDataFrame.retype(stock)
|
||||
kdjj = int(stockStat["kdjj"].tail(1).values[0])
|
||||
rsi_6 = int(stockStat["rsi_6"].tail(1).values[0])
|
||||
cci = int(stockStat["cci"].tail(1).values[0])
|
||||
print("kdjj:", kdjj, "rsi_6:", rsi_6, "cci:", cci)
|
||||
# and kdjj > 80 and rsi_6 > 55 and cci > 100 判断卖出时刻。也就是买入时刻的反面。发现有波动就卖了。
|
||||
# if kdjj <= 10 and rsi_6 <= 50 and cci <= 100: old
|
||||
if kdjj <= 80 or rsi_6 <= 55 or cci <= 100:
|
||||
return list([0, code, date, 1, cci, kdjj, rsi_6])
|
||||
else:
|
||||
return list([1, code, date, 0, cci, kdjj, rsi_6])
|
||||
|
||||
|
||||
# 增加 收益计算。
|
||||
def stat_index_calculate(tmp_datetime):
|
||||
# 要操作的数据库表名称。
|
||||
table_name = "guess_indicators_lite_sell_daily"
|
||||
datetime_str = (tmp_datetime).strftime("%Y-%m-%d")
|
||||
datetime_int = (tmp_datetime).strftime("%Y%m%d")
|
||||
print("datetime_str:", datetime_str)
|
||||
print("datetime_int:", datetime_int)
|
||||
|
||||
sql_1 = """
|
||||
SELECT `buy_date`, `code`, `name`, `changepercent`, `trade`, `turnoverratio`, `pb`, `kdjj`, `rsi_6`,
|
||||
`cci`, `wave_base`, `wave_crest`, `wave_mean`, `up_rate`
|
||||
FROM guess_indicators_lite_buy_daily where `buy_date` <= """ + datetime_int
|
||||
print(sql_1)
|
||||
data = pd.read_sql(sql=sql_1, con=common.engine(), params=[])
|
||||
data = data.drop_duplicates(subset="code", keep="last")
|
||||
print(data["trade"])
|
||||
data["trade_float32"] = data["trade"].astype('float32', copy=False)
|
||||
print(len(data))
|
||||
data["date"] = datetime_int
|
||||
|
||||
stock_merge = pd.DataFrame({
|
||||
"date": data["date"], "code": data["code"], "today_trade": data["trade"]}, index=data.index.values)
|
||||
print(stock_merge.head(1))
|
||||
|
||||
stock_merge = stock_merge.apply(apply_merge, axis=1) # , axis=1)
|
||||
|
||||
del stock_merge["date"] # 合并前删除 date 字段。
|
||||
# 合并数据
|
||||
data_new = pd.merge(data, stock_merge, on=['code'], how='left')
|
||||
data_new["income"] = (data_new["today_trade"] - data_new["trade_float32"]) * 100
|
||||
data_new["income"] = data_new["income"].round(4) # 保留4位小数。
|
||||
|
||||
# 增加售出列。看看是否需要卖出。
|
||||
stock_sell_merge = pd.DataFrame({
|
||||
"date": data["date"], "code": data["code"], "sell": 0, "buy": 0, "sell_kdjj": 0, "sell_rsi_6": 0,
|
||||
"sell_cci": 0},
|
||||
index=data.index.values)
|
||||
print(stock_sell_merge.head(1))
|
||||
|
||||
merge_sell_data = stock_sell_merge.apply(apply_merge_sell, axis=1) # , axis=1)
|
||||
# 重命名
|
||||
del merge_sell_data["date"] # 合并前删除 date 字段。
|
||||
# 合并数据
|
||||
data_new = pd.merge(data_new, merge_sell_data, on=['code'], how='left')
|
||||
|
||||
# 删除老数据。
|
||||
try:
|
||||
del_sql = " DELETE FROM `stock_data`.`" + table_name + "` WHERE `date`= '%s' " % datetime_int
|
||||
common.insert(del_sql)
|
||||
print("insert_db")
|
||||
except Exception as e:
|
||||
print("error :", e)
|
||||
del data_new["trade_float32"]
|
||||
try:
|
||||
common.insert_db(data_new, table_name, False, "`date`,`code`")
|
||||
print("insert_db")
|
||||
except Exception as e:
|
||||
print("error :", e)
|
||||
# 重命名
|
||||
del data_new["name"]
|
||||
print(data_new)
|
||||
|
||||
|
||||
# main函数入口
|
||||
if __name__ == '__main__':
|
||||
# 计算买卖。
|
||||
tmp_datetime = common.run_with_args(stat_index_calculate)
|
||||
@@ -0,0 +1,119 @@
|
||||
#!/usr/local/bin/python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
|
||||
import libs.common as common
|
||||
import sys
|
||||
import time
|
||||
import pandas as pd
|
||||
import tushare as ts
|
||||
from sqlalchemy.types import NVARCHAR
|
||||
from sqlalchemy import inspect
|
||||
import datetime
|
||||
import heapq
|
||||
|
||||
"""
|
||||
SELECT `date`, `code`, `name`, `changepercent`, `trade`, `open`, `high`, `low`,
|
||||
`settlement`, `volume`, `turnoverratio`, `amount`, `per`, `pb`, `mktcap`, `nmc`
|
||||
FROM stock_data.ts_today_all where `date` = 20171106 and trade > 0 and trade <= 20
|
||||
and `code` not like '002%' and `code` not like '300%' and `name` not like '%st%'
|
||||
|
||||
"""
|
||||
|
||||
|
||||
def stat_index_all(tmp_datetime):
|
||||
datetime_str = (tmp_datetime).strftime("%Y-%m-%d")
|
||||
datetime_int = (tmp_datetime).strftime("%Y%m%d")
|
||||
print("datetime_str:", datetime_str)
|
||||
print("datetime_int:", datetime_int)
|
||||
|
||||
# 查询今日满足股票数据。剔除数据:创业板股票数据,中小板股票数据,所有st股票
|
||||
# #`code` not like '002%' and `code` not like '300%' and `name` not like '%st%'
|
||||
sql_1 = """
|
||||
SELECT `date`, `code`, `name`, `changepercent`, `trade`, `open`, `high`, `low`,
|
||||
`settlement`, `volume`, `turnoverratio`, `amount`, `per`, `pb`, `mktcap`, `nmc`
|
||||
FROM stock_data.ts_today_all WHERE `date` = %s and `trade` > 0 and `open` > 0 and trade <= 20
|
||||
and `code` not like %s and `code` not like %s and `name` not like %s
|
||||
"""
|
||||
print(sql_1)
|
||||
data = pd.read_sql(sql=sql_1, con=common.engine(), params=[datetime_int, '002%', '300%', '%st%'])
|
||||
print(type(data))
|
||||
data = data.drop_duplicates(subset="code", keep="last")
|
||||
print(data["trade"])
|
||||
data["trade_float32"] = data["trade"].astype('float32', copy=False)
|
||||
print(len(data))
|
||||
print("########data[trade]########:")
|
||||
print(data["trade"])
|
||||
|
||||
# 使用 trade 填充数据
|
||||
stock_guess = pd.DataFrame({
|
||||
"date": data["date"], "code": data["code"], "wave_mean": data["trade"],
|
||||
"wave_crest": data["trade"], "wave_base": data["trade"]}, index=data.index.values)
|
||||
print(stock_guess.head())
|
||||
stock_guess = stock_guess.apply(apply_guess, axis=1) # , axis=1)
|
||||
print(stock_guess.head())
|
||||
# stock_guess.astype('float32', copy=False)
|
||||
stock_guess.drop('date', axis=1, inplace=True) # 删除日期字段,然后和原始数据合并。
|
||||
stock_guess = stock_guess.round(2) # 数据保留2位小数
|
||||
print(stock_guess["wave_base"])
|
||||
|
||||
data_new = pd.merge(data, stock_guess, on=['code'], how='left')
|
||||
print("#############")
|
||||
|
||||
# 使用pandas 函数 : https://pandas.pydata.org/pandas-docs/stable/api.html#id4
|
||||
data_new["up_rate"] = (data_new["trade_float32"].sub(data_new["wave_mean"])).div(data_new["wave_crest"]).mul(100)
|
||||
data_new["up_rate"] = data_new["up_rate"].round(2) # 数据保留2位小数
|
||||
data_new.drop('trade_float32', axis=1, inplace=True) # 删除计算字段。
|
||||
|
||||
# 删除老数据。
|
||||
del_sql = " DELETE FROM `stock_data`.`guess_period_daily` WHERE `date`= '%s' " % datetime_int
|
||||
common.insert(del_sql)
|
||||
# print(data_new.head())
|
||||
# data_new["down_rate"] = (data_new["trade"] - data_new["wave_mean"]) / data_new["wave_base"]
|
||||
common.insert_db(data_new, "guess_period_daily", False, "`date`,`code`")
|
||||
|
||||
# 进行左连接.
|
||||
# tmp = pd.merge(tmp, tmp2, on=['company_id'], how='left')
|
||||
|
||||
|
||||
def apply_guess(tmp):
|
||||
date = tmp["date"]
|
||||
code = tmp["code"]
|
||||
date_end = datetime.datetime.strptime(date, "%Y%m%d")
|
||||
date_start = (date_end + datetime.timedelta(days=-300)).strftime("%Y-%m-%d")
|
||||
date_end = date_end.strftime("%Y-%m-%d")
|
||||
print(code, date_start, date_end)
|
||||
|
||||
# open, high, close, low, volume, price_change, p_change, ma5, ma10, ma20, v_ma5, v_ma10, v_ma20, turnover
|
||||
# 使用缓存方法。加快计算速度。
|
||||
stock = common.get_hist_data_cache(code, date_start, date_end)
|
||||
# 增加空判断,如果是空返回 0 数据。
|
||||
if stock is None:
|
||||
return pd.Series([date, code, 0.0, 0.0, 0.0],
|
||||
index=['date', 'code', 'wave_mean', 'wave_crest', 'wave_base'])
|
||||
|
||||
stock = pd.DataFrame({"close": stock["close"]}, index=stock.index.values)
|
||||
stock = stock.sort_index(0) # 将数据按照日期排序下。
|
||||
|
||||
# print(stock.head(10))
|
||||
arr = pd.Series(stock["close"].values)
|
||||
# print(df_arr)
|
||||
wave_mean = arr.mean()
|
||||
# 计算股票的波峰值。
|
||||
wave_crest = heapq.nlargest(5, enumerate(arr), key=lambda x: x[1])
|
||||
wave_crest_mean = pd.DataFrame(wave_crest).mean()
|
||||
|
||||
# 输出元祖第一个元素是index,第二元素是比较的数值 计算数据的波谷值
|
||||
wave_base = heapq.nsmallest(5, enumerate(arr), key=lambda x: x[1])
|
||||
wave_base_mean = pd.DataFrame(wave_base).mean()
|
||||
# 输出数据
|
||||
# print("##############")
|
||||
# code date wave_base wave_crest wave_mean 顺序必须一致。返回的是行数据,然后填充。
|
||||
return pd.Series([date, code, wave_base_mean[1], wave_crest_mean[1], wave_mean],
|
||||
index=['date','code','wave_mean','wave_crest','wave_base'])
|
||||
|
||||
|
||||
# main函数入口
|
||||
if __name__ == '__main__':
|
||||
# 使用方法传递。
|
||||
tmp_datetime = common.run_with_args(stat_index_all)
|
||||
@@ -0,0 +1,130 @@
|
||||
#!/usr/local/bin/python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
|
||||
import libs.common as common
|
||||
import sys
|
||||
import time
|
||||
import pandas as pd
|
||||
import numpy as np
|
||||
import math
|
||||
import tushare as ts
|
||||
from sqlalchemy.types import NVARCHAR
|
||||
from sqlalchemy import inspect
|
||||
import datetime
|
||||
import heapq
|
||||
|
||||
"""
|
||||
SELECT `date`, `code`, `name`, `changepercent`, `trade`, `open`, `high`, `low`,
|
||||
`settlement`, `volume`, `turnoverratio`, `amount`, `per`, `pb`, `mktcap`, `nmc`
|
||||
FROM stock_data.ts_today_all where `date` = 20171106 and trade > 0 and trade <= 20
|
||||
and `code` not like '002%' and `code` not like '300%' and `name` not like '%st%'
|
||||
|
||||
"""
|
||||
|
||||
|
||||
def stat_index_all(tmp_datetime):
|
||||
datetime_str = (tmp_datetime).strftime("%Y-%m-%d")
|
||||
datetime_int = (tmp_datetime).strftime("%Y%m%d")
|
||||
print("datetime_str:", datetime_str)
|
||||
print("datetime_int:", datetime_int)
|
||||
|
||||
# 查询今日满足股票数据。剔除数据:创业板股票数据,中小板股票数据,所有st股票
|
||||
# #`code` not like '002%' and `code` not like '300%' and `name` not like '%st%'
|
||||
sql_1 = """
|
||||
SELECT `date`, `code`, `name`, `changepercent`, `trade`, `open`, `high`, `low`,
|
||||
`settlement`, `volume`, `turnoverratio`, `amount`, `per`, `pb`, `mktcap`, `nmc`
|
||||
FROM stock_data.ts_today_all WHERE `date` = %s and `trade` > 0 and `open` > 0 and trade <= 20
|
||||
and `code` not like %s and `code` not like %s and `name` not like %s
|
||||
"""
|
||||
print(sql_1)
|
||||
data = pd.read_sql(sql=sql_1, con=common.engine(), params=[datetime_int, '002%', '300%', '%st%'])
|
||||
data = data.drop_duplicates(subset="code", keep="last")
|
||||
print("########data[trade]########:")
|
||||
# print(data["trade"])
|
||||
|
||||
# 使用 trade 填充数据
|
||||
stock_guess = pd.DataFrame({
|
||||
"date": data["date"], "code": data["code"], "5d": data["trade"],
|
||||
"10d": data["trade"], "20d": data["trade"], "60d": data["trade"], "5-10d": data["trade"],
|
||||
"5-20d": data["trade"], "return": data["trade"], "mov_vol": data["trade"]
|
||||
}, index=data.index.values)
|
||||
|
||||
stock_guess = stock_guess.apply(apply_guess, axis=1) # , axis=1)
|
||||
# print(stock_guess.head())
|
||||
# stock_guess.astype('float32', copy=False)
|
||||
stock_guess.drop('date', axis=1, inplace=True) # 删除日期字段,然后和原始数据合并。
|
||||
|
||||
# print(stock_guess["5d"])
|
||||
|
||||
data_new = pd.merge(data, stock_guess, on=['code'], how='left')
|
||||
print("#############")
|
||||
|
||||
# 使用pandas 函数 : https://pandas.pydata.org/pandas-docs/stable/api.html#id4
|
||||
data_new["return"] = data_new["return"].mul(100) # 扩大100 倍方便观察
|
||||
data_new["mov_vol"] = data_new["mov_vol"].mul(100)
|
||||
|
||||
data_new = data_new.round(2) # 数据保留2位小数
|
||||
|
||||
# 删除老数据。
|
||||
del_sql = " DELETE FROM `stock_data`.`guess_return_daily` WHERE `date`= '%s' " % datetime_int
|
||||
common.insert(del_sql)
|
||||
|
||||
# data_new["down_rate"] = (data_new["trade"] - data_new["wave_mean"]) / data_new["wave_base"]
|
||||
common.insert_db(data_new, "guess_return_daily", False, "`date`,`code`")
|
||||
|
||||
# 进行左连接.
|
||||
# tmp = pd.merge(tmp, tmp2, on=['company_id'], how='left')
|
||||
|
||||
|
||||
def apply_guess(tmp):
|
||||
date = tmp["date"]
|
||||
code = tmp["code"]
|
||||
date_end = datetime.datetime.strptime(date, "%Y%m%d")
|
||||
date_start = (date_end + datetime.timedelta(days=-300)).strftime("%Y-%m-%d")
|
||||
date_end = date_end.strftime("%Y-%m-%d")
|
||||
print(code, date_start, date_end)
|
||||
# open, high, close, low, volume, price_change, p_change, ma5, ma10, ma20, v_ma5, v_ma10, v_ma20, turnover
|
||||
# 使用缓存方法。加快计算速度。
|
||||
stock = common.get_hist_data_cache(code, date_start, date_end)
|
||||
# 增加空判断,如果是空返回 0 数据。
|
||||
if stock is None:
|
||||
return pd.Series([0.0, 0.0, 0.0, 0.0, 0.0, 0.0, code, date, 0.0, 0.0],
|
||||
index=['10d', '20d', '5-10d', '5-20d', '5d', '60d', 'code', 'date', 'mov_vol', 'return'])
|
||||
|
||||
stock = pd.DataFrame({"close": stock["close"]}, index=stock.index.values)
|
||||
stock = stock.sort_index(0) # 将数据按照日期排序下。
|
||||
# print(stock.head(10))
|
||||
# 5周期、10周期、20周期和60周期
|
||||
# 周线、半月线、月线和季度线
|
||||
stock["5d"] = stock["close"].rolling(window=5).mean() # 周线
|
||||
stock["10d"] = stock["close"].rolling(window=10).mean() # 半月线
|
||||
stock["20d"] = stock["close"].rolling(window=20).mean() # 月线
|
||||
stock["60d"] = stock["close"].rolling(window=60).mean() # 季度线
|
||||
# 计算日期差。
|
||||
stock["5-10d"] = (stock["5d"] - stock["10d"]) * 100 / stock["10d"] # 周-半月线差
|
||||
stock["5-20d"] = (stock["5d"] - stock["20d"]) * 100 / stock["20d"] # 周-月线差
|
||||
# 计算股票的收益价格
|
||||
stock["return"] = np.log(stock["close"] / stock["close"].shift(1))
|
||||
|
||||
# print(stock["return"])
|
||||
# 计算股票的【收益率的移动历史标准差】
|
||||
mov_day = int(len(stock) / 20)
|
||||
# print("mov_day:", mov_day, len(stock))
|
||||
stock["mov_vol"] = stock["return"].rolling(window=mov_day).std() * math.sqrt(mov_day)
|
||||
# print(stock["mov_vol"].tail())
|
||||
# print(stock["return"].tail())
|
||||
# print("stock[10d].tail(1)", stock["10d"].tail(1).values[0])
|
||||
# 10d 20d 5-10d 5-20d 5d 60d code date mov_vol return
|
||||
tmp = pd.Series([stock["10d"].tail(1).values[0], stock["20d"].tail(1).values[0], stock["5-10d"].tail(1).values[0],
|
||||
stock["5-20d"].tail(1).values[0], stock["5d"].tail(1).values[0], stock["60d"].tail(1).values[0],
|
||||
code, date, stock["mov_vol"].tail(1).values[0], stock["return"].tail(1).values[0]],
|
||||
index=['10d', '20d', '5-10d', '5-20d', '5d', '60d', 'code', 'date', 'mov_vol', 'return'])
|
||||
# print(tmp)
|
||||
return tmp
|
||||
|
||||
|
||||
# main函数入口
|
||||
if __name__ == '__main__':
|
||||
# 使用方法传递。
|
||||
tmp_datetime = common.run_with_args(stat_index_all)
|
||||
@@ -0,0 +1,146 @@
|
||||
#!/usr/local/bin/python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
|
||||
import libs.common as common
|
||||
import pandas as pd
|
||||
import numpy as np
|
||||
import math
|
||||
import datetime
|
||||
import sklearn as skl
|
||||
from sklearn import datasets, linear_model
|
||||
# https://github.com/udacity/machine-learning/issues/202
|
||||
# sklearn.cross_validation 这个包不推荐使用了。
|
||||
from sklearn.model_selection import train_test_split, cross_val_score
|
||||
from sklearn.neighbors import KNeighborsClassifier
|
||||
|
||||
# 要操作的数据库表名称。
|
||||
table_name = "guess_sklearn_ma_daily"
|
||||
|
||||
|
||||
# 批处理数据。
|
||||
def stat_all_batch(tmp_datetime):
|
||||
datetime_str = (tmp_datetime).strftime("%Y-%m-%d")
|
||||
datetime_int = (tmp_datetime).strftime("%Y%m%d")
|
||||
print("datetime_str:", datetime_str)
|
||||
print("datetime_int:", datetime_int)
|
||||
|
||||
try:
|
||||
# 删除老数据。
|
||||
del_sql = " DELETE FROM `stock_data`.`%s` WHERE `date`= %s " % (table_name, datetime_int)
|
||||
print("del_sql:", del_sql)
|
||||
common.insert(del_sql)
|
||||
except Exception as e:
|
||||
print("error :", e)
|
||||
|
||||
sql_count = """
|
||||
SELECT count(1) FROM stock_data.ts_today_all WHERE `date` = %s and `trade` > 0 and `open` > 0 and trade <= 20
|
||||
and `code` not like %s and `name` not like %s
|
||||
"""
|
||||
# 修改逻辑,增加中小板块计算。 中小板:002,创业板:300 。and `code` not like %s and `code` not like %s and `name` not like %s
|
||||
# count = common.select_count(sql_count, params=[datetime_int, '002%', '300%', '%st%'])
|
||||
count = common.select_count(sql_count, params=[datetime_int, '300%', '%st%'])
|
||||
print("count :", count)
|
||||
batch_size = 100
|
||||
end = int(math.ceil(float(count) / batch_size) * batch_size)
|
||||
print(end)
|
||||
# for i in range(0, end, batch_size):
|
||||
for i in range(0, end, batch_size):
|
||||
print("loop :", i)
|
||||
# 查询今日满足股票数据。剔除数据:创业板股票数据,中小板股票数据,所有st股票
|
||||
# #`code` not like '002%' and `code` not like '300%' and `name` not like '%st%'
|
||||
sql_1 = """
|
||||
SELECT `date`, `code`, `name`, `changepercent`, `trade`, `open`, `high`, `low`,
|
||||
`settlement`, `volume`, `turnoverratio`, `amount`, `per`, `pb`, `mktcap`, `nmc`
|
||||
FROM stock_data.ts_today_all WHERE `date` = %s and `trade` > 0 and `open` > 0 and trade <= 20
|
||||
and `code` not like %s and `name` not like %s limit %s , %s
|
||||
"""
|
||||
print(sql_1)
|
||||
# data = pd.read_sql(sql=sql_1, con=common.engine(), params=[datetime_int, '002%', '300%', '%st%', i, batch_size])
|
||||
data = pd.read_sql(sql=sql_1, con=common.engine(), params=[datetime_int, '300%', '%st%', i, batch_size])
|
||||
data = data.drop_duplicates(subset="code", keep="last")
|
||||
print("########data[trade]########:", len(data))
|
||||
|
||||
# 使用 trade 填充数据
|
||||
stock_sklearn = pd.DataFrame({
|
||||
"date": data["date"], "code": data["code"], "next_close": data["trade"],
|
||||
"sklearn_score": data["trade"]}, index=data.index.values)
|
||||
print(stock_sklearn.head())
|
||||
stock_sklearn_apply = stock_sklearn.apply(apply_sklearn, axis=1) # , axis=1)
|
||||
# 重命名
|
||||
del stock_sklearn_apply["date"] # 合并前删除 date 字段。
|
||||
# 合并数据
|
||||
data_new = pd.merge(data, stock_sklearn_apply, on=['code'], how='left')
|
||||
# for index, row in data.iterrows():
|
||||
# next_stock, score = stat_index_all(row, i)
|
||||
# print(next_stock, score)
|
||||
data_new["next_close"] = data_new["next_close"].round(2) # 数据保留4位小数
|
||||
data_new["sklearn_score"] = data_new["sklearn_score"].round(2) # 数据保留2位小数
|
||||
|
||||
data_new["trade_float32"] = data["trade"].astype('float32', copy=False)
|
||||
data_new["up_rate"] = (data_new["next_close"] - data_new["trade_float32"]) * 100 / data_new["trade_float32"]
|
||||
data_new["up_rate"] = data_new["up_rate"].round(2) # 数据保留2位小数
|
||||
del data_new["trade_float32"]
|
||||
|
||||
try:
|
||||
common.insert_db(data_new, table_name, False, "`date`,`code`")
|
||||
print("insert_db")
|
||||
except Exception as e:
|
||||
print("error :", e)
|
||||
# 重命名
|
||||
del data_new["name"]
|
||||
print(data_new)
|
||||
|
||||
|
||||
# code date next_close sklearn_score
|
||||
def apply_sklearn(data):
|
||||
# 要操作的数据库表名称。
|
||||
print("########stat_index_all########:", len(data))
|
||||
date = data["date"]
|
||||
code = data["code"]
|
||||
print(date, code)
|
||||
date_end = datetime.datetime.strptime(date, "%Y%m%d")
|
||||
date_start = (date_end + datetime.timedelta(days=-300)).strftime("%Y-%m-%d")
|
||||
date_end = date_end.strftime("%Y-%m-%d")
|
||||
print(code, date_start, date_end)
|
||||
|
||||
# open high close low volume price_change p_change ma5 ma10 ma20 v_ma5 v_ma10 v_ma20 turnover
|
||||
stock_X = common.get_hist_data_cache(code, date_start, date_end)
|
||||
# 增加空判断,如果是空返回 0 数据。
|
||||
if stock_X is None:
|
||||
return list([code, date, 0.0, 0.0])
|
||||
|
||||
stock_X = stock_X.sort_index(0) # 将数据按照日期排序下。
|
||||
stock_y = pd.Series(stock_X["close"].values) # 标签
|
||||
|
||||
stock_X_next = stock_X.iloc[len(stock_X) - 1]
|
||||
print("########################### stock_X_next date:", stock_X_next)
|
||||
# 使用今天的交易价格,13 个指标预测明天的价格。偏移股票数据,今天的数据,目标是明天的价格。
|
||||
stock_X = stock_X.drop(stock_X.index[len(stock_X) - 1]) # 删除最后一条数据
|
||||
stock_y = stock_y.drop(stock_y.index[0]) # 删除第一条数据
|
||||
# print("########################### stock_X date:", stock_X)
|
||||
|
||||
# 删除掉close 也就是收盘价格。
|
||||
del stock_X["close"]
|
||||
del stock_X_next["close"]
|
||||
|
||||
model = linear_model.LinearRegression()
|
||||
# model = KNeighborsClassifier()
|
||||
|
||||
model.fit(stock_X.values, stock_y)
|
||||
# print("############## test_akshare & target #############")
|
||||
# print("############## coef_ & intercept_ #############")
|
||||
# print(model.coef_) # 系数
|
||||
# print(model.intercept_) # 截断
|
||||
next_close = model.predict([stock_X_next.values])
|
||||
if len(next_close) == 1:
|
||||
next_close = next_close[0]
|
||||
sklearn_score = model.score(stock_X.values, stock_y)
|
||||
print("score:", sklearn_score) # 评分
|
||||
return list([code, date, next_close, sklearn_score * 100])
|
||||
|
||||
|
||||
# main函数入口
|
||||
if __name__ == '__main__':
|
||||
# 使用方法传递。
|
||||
tmp_datetime = common.run_with_args(stat_all_batch)
|
||||
@@ -0,0 +1,148 @@
|
||||
; Sample supervisor config file.
|
||||
;
|
||||
; For more information on the config file, please see:
|
||||
; http://supervisord.org/configuration.html
|
||||
;
|
||||
; Notes:
|
||||
; - Shell expansion ("~" or "$HOME") is not supported. Environment
|
||||
; variables can be expanded using this syntax: "%(ENV_HOME)s".
|
||||
; - Quotes around values are not supported, except in the case of
|
||||
; the environment= options as shown below.
|
||||
; - Comments must have a leading space: "a=b ;comment" not "a=b;comment".
|
||||
; - Command will be truncated if it looks like a config file comment, e.g.
|
||||
; "command=bash -c 'foo ; bar'" will truncate to "command=bash -c 'foo ".
|
||||
|
||||
[unix_http_server]
|
||||
file=/tmp/supervisor.sock ; the path to the socket file
|
||||
;chmod=0700 ; socket file mode (default 0700)
|
||||
;chown=nobody:nogroup ; socket file uid:gid owner
|
||||
;username=user ; default is no username (open server)
|
||||
;password=123 ; default is no password (open server)
|
||||
|
||||
;[inet_http_server] ; inet (TCP) server disabled by default
|
||||
;port=127.0.0.1:9001 ; ip_address:port specifier, *:port for all iface
|
||||
;username=user ; default is no username (open server)
|
||||
;password=123 ; default is no password (open server)
|
||||
|
||||
[supervisord]
|
||||
logfile=/tmp/supervisord.log ; main log file; default $CWD/supervisord.log
|
||||
logfile_maxbytes=50MB ; max main logfile bytes b4 rotation; default 50MB
|
||||
logfile_backups=10 ; # of main logfile backups; 0 means none, default 10
|
||||
loglevel=info ; log level; default info; others: debug,warn,trace
|
||||
pidfile=/tmp/supervisord.pid ; supervisord pidfile; default supervisord.pid
|
||||
nodaemon=false ; start in foreground if true; default false
|
||||
minfds=1024 ; min. avail startup file descriptors; default 1024
|
||||
minprocs=200 ; min. avail process descriptors;default 200
|
||||
;umask=022 ; process file creation umask; default 022
|
||||
;user=chrism ; default is current user, required if root
|
||||
;identifier=supervisor ; supervisord identifier, default is 'supervisor'
|
||||
;directory=/tmp ; default is not to cd during start
|
||||
;nocleanup=true ; don't clean up tempfiles at start; default false
|
||||
;childlogdir=/tmp ; 'AUTO' child log dir, default $TEMP
|
||||
;environment=KEY="value" ; key value pairs to add to environment
|
||||
;strip_ansi=false ; strip ansi escape codes in logs; def. false
|
||||
|
||||
; The rpcinterface:supervisor section must remain in the config file for
|
||||
; RPC (supervisorctl/web interface) to work. Additional interfaces may be
|
||||
; added by defining them in separate [rpcinterface:x] sections.
|
||||
|
||||
[rpcinterface:supervisor]
|
||||
supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface
|
||||
|
||||
; The supervisorctl section configures how supervisorctl will connect to
|
||||
; supervisord. configure it match the settings in either the unix_http_server
|
||||
; or inet_http_server section.
|
||||
|
||||
[supervisorctl]
|
||||
serverurl=unix:///tmp/supervisor.sock ; use a unix:// URL for a unix socket
|
||||
;serverurl=http://127.0.0.1:9001 ; use an http:// url to specify an inet socket
|
||||
;username=chris ; should be same as in [*_http_server] if set
|
||||
;password=123 ; should be same as in [*_http_server] if set
|
||||
;prompt=mysupervisor ; cmd line prompt (default "supervisor")
|
||||
;history_file=~/.sc_history ; use readline history if available
|
||||
|
||||
; The sample program section below shows all possible program subsection values.
|
||||
; Create one or more 'real' program: sections to be able to control them under
|
||||
; supervisor.
|
||||
|
||||
;[program:theprogramname]
|
||||
;command=/bin/cat ; the program (relative uses PATH, can take args)
|
||||
;process_name=%(program_name)s ; process_name expr (default %(program_name)s)
|
||||
;numprocs=1 ; number of processes copies to start (def 1)
|
||||
;directory=/tmp ; directory to cwd to before exec (def no cwd)
|
||||
;umask=022 ; umask for process (default None)
|
||||
;priority=999 ; the relative start priority (default 999)
|
||||
;autostart=true ; start at supervisord start (default: true)
|
||||
;startsecs=1 ; # of secs prog must stay up to be running (def. 1)
|
||||
;startretries=3 ; max # of serial start failures when starting (default 3)
|
||||
;autorestart=unexpected ; when to restart if exited after running (def: unexpected)
|
||||
;exitcodes=0,2 ; 'expected' exit codes used with autorestart (default 0,2)
|
||||
;stopsignal=QUIT ; signal used to kill process (default TERM)
|
||||
;stopwaitsecs=10 ; max num secs to wait b4 SIGKILL (default 10)
|
||||
;stopasgroup=false ; send stop signal to the UNIX process group (default false)
|
||||
;killasgroup=false ; SIGKILL the UNIX process group (def false)
|
||||
;user=chrism ; setuid to this UNIX account to run the program
|
||||
;redirect_stderr=true ; redirect proc stderr to stdout (default false)
|
||||
;stdout_logfile=/a/path ; stdout log path, NONE for none; default AUTO
|
||||
;stdout_logfile_maxbytes=1MB ; max # logfile bytes b4 rotation (default 50MB)
|
||||
;stdout_logfile_backups=10 ; # of stdout logfile backups (0 means none, default 10)
|
||||
;stdout_capture_maxbytes=1MB ; number of bytes in 'capturemode' (default 0)
|
||||
;stdout_events_enabled=false ; emit events on stdout writes (default false)
|
||||
;stderr_logfile=/a/path ; stderr log path, NONE for none; default AUTO
|
||||
;stderr_logfile_maxbytes=1MB ; max # logfile bytes b4 rotation (default 50MB)
|
||||
;stderr_logfile_backups=10 ; # of stderr logfile backups (0 means none, default 10)
|
||||
;stderr_capture_maxbytes=1MB ; number of bytes in 'capturemode' (default 0)
|
||||
;stderr_events_enabled=false ; emit events on stderr writes (default false)
|
||||
;environment=A="1",B="2" ; process environment additions (def no adds)
|
||||
;serverurl=AUTO ; override serverurl computation (childutils)
|
||||
|
||||
; The sample eventlistener section below shows all possible eventlistener
|
||||
; subsection values. Create one or more 'real' eventlistener: sections to be
|
||||
; able to handle event notifications sent by supervisord.
|
||||
|
||||
;[eventlistener:theeventlistenername]
|
||||
;command=/bin/eventlistener ; the program (relative uses PATH, can take args)
|
||||
;process_name=%(program_name)s ; process_name expr (default %(program_name)s)
|
||||
;numprocs=1 ; number of processes copies to start (def 1)
|
||||
;events=EVENT ; event notif. types to subscribe to (req'd)
|
||||
;buffer_size=10 ; event buffer queue size (default 10)
|
||||
;directory=/tmp ; directory to cwd to before exec (def no cwd)
|
||||
;umask=022 ; umask for process (default None)
|
||||
;priority=-1 ; the relative start priority (default -1)
|
||||
;autostart=true ; start at supervisord start (default: true)
|
||||
;startsecs=1 ; # of secs prog must stay up to be running (def. 1)
|
||||
;startretries=3 ; max # of serial start failures when starting (default 3)
|
||||
;autorestart=unexpected ; autorestart if exited after running (def: unexpected)
|
||||
;exitcodes=0,2 ; 'expected' exit codes used with autorestart (default 0,2)
|
||||
;stopsignal=QUIT ; signal used to kill process (default TERM)
|
||||
;stopwaitsecs=10 ; max num secs to wait b4 SIGKILL (default 10)
|
||||
;stopasgroup=false ; send stop signal to the UNIX process group (default false)
|
||||
;killasgroup=false ; SIGKILL the UNIX process group (def false)
|
||||
;user=chrism ; setuid to this UNIX account to run the program
|
||||
;redirect_stderr=false ; redirect_stderr=true is not allowed for eventlisteners
|
||||
;stdout_logfile=/a/path ; stdout log path, NONE for none; default AUTO
|
||||
;stdout_logfile_maxbytes=1MB ; max # logfile bytes b4 rotation (default 50MB)
|
||||
;stdout_logfile_backups=10 ; # of stdout logfile backups (0 means none, default 10)
|
||||
;stdout_events_enabled=false ; emit events on stdout writes (default false)
|
||||
;stderr_logfile=/a/path ; stderr log path, NONE for none; default AUTO
|
||||
;stderr_logfile_maxbytes=1MB ; max # logfile bytes b4 rotation (default 50MB)
|
||||
;stderr_logfile_backups=10 ; # of stderr logfile backups (0 means none, default 10)
|
||||
;stderr_events_enabled=false ; emit events on stderr writes (default false)
|
||||
;environment=A="1",B="2" ; process environment additions
|
||||
;serverurl=AUTO ; override serverurl computation (childutils)
|
||||
|
||||
; The sample group section below shows all possible group values. Create one
|
||||
; or more 'real' group: sections to create "heterogeneous" process groups.
|
||||
|
||||
;[group:thegroupname]
|
||||
;programs=progname1,progname2 ; each refers to 'x' in [program:x] definitions
|
||||
;priority=999 ; the relative start priority (default 999)
|
||||
|
||||
; The [include] section can just contain the "files" setting. This
|
||||
; setting can list multiple files (separated by whitespace or
|
||||
; newlines). It can also contain wildcards. The filenames are
|
||||
; interpreted as relative to this file. Included files *cannot*
|
||||
; include files themselves.
|
||||
|
||||
;[include]
|
||||
;files = relative/directory/*.ini
|
||||
@@ -0,0 +1,51 @@
|
||||
[unix_http_server]
|
||||
file=/tmp/supervisor.sock ; the path to the socket file
|
||||
|
||||
[inet_http_server] ; inet (TCP) server disabled by default
|
||||
port=*:9001 ; ip_address:port specifier, *:port for all iface
|
||||
;username=user ; default is no username (open server)
|
||||
;password=123 ; default is no password (open server)
|
||||
|
||||
[supervisord]
|
||||
logfile=/tmp/supervisord.log ; main log file; default $CWD/supervisord.log
|
||||
logfile_maxbytes=50MB ; max main logfile bytes b4 rotation; default 50MB
|
||||
logfile_backups=10 ; # of main logfile backups; 0 means none, default 10
|
||||
loglevel=info ; log level; default info; others: debug,warn,trace
|
||||
pidfile=/tmp/supervisord.pid ; supervisord pidfile; default supervisord.pid
|
||||
nodaemon=false ; start in foreground if true; default false
|
||||
minfds=1024 ; min. avail startup file descriptors; default 1024
|
||||
minprocs=200 ; min. avail process descriptors;default 200
|
||||
|
||||
[rpcinterface:supervisor]
|
||||
supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface
|
||||
|
||||
[supervisorctl]
|
||||
serverurl=unix:///tmp/supervisor.sock ; use a unix:// URL for a unix socket
|
||||
|
||||
[program:init]
|
||||
command=/data/stock/jobs/run_init.sh
|
||||
autostart=true
|
||||
autorestart=true
|
||||
startsecs=20
|
||||
priority=1
|
||||
stopasgroup=true
|
||||
killasgroup=true
|
||||
|
||||
[program:cron]
|
||||
command=/data/stock/jobs/run_cron.sh
|
||||
autostart=true
|
||||
autorestart=true
|
||||
startsecs=20
|
||||
priority=1
|
||||
stopasgroup=true
|
||||
killasgroup=true
|
||||
|
||||
|
||||
[program:stock-web]
|
||||
command=/data/stock/jobs/run_web.sh
|
||||
autostart=true
|
||||
autorestart=true
|
||||
startsecs=20
|
||||
priority=1
|
||||
stopasgroup=true
|
||||
killasgroup=true
|
||||
Executable
+46
@@ -0,0 +1,46 @@
|
||||
#!/usr/local/bin/python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import tornado.web
|
||||
import libs.stock_web_dic as stock_web_dic
|
||||
import libs.common as common
|
||||
import logging
|
||||
|
||||
#基础handler,主要负责检查mysql的数据库链接。
|
||||
class BaseHandler(tornado.web.RequestHandler):
|
||||
def set_default_headers(self):
|
||||
headers = self.request.headers
|
||||
# logging.info('head的类型:',type(headers))
|
||||
origin = headers.get('origin',None)
|
||||
logging.info("######################## BaseHandler ########################")
|
||||
logging.info(origin)
|
||||
|
||||
if origin != None and origin.find("localhost") > 0:
|
||||
self.set_header("Access-Control-Allow-Credentials", "true")
|
||||
self.set_header("Access-Control-Allow-Origin",origin)
|
||||
self.set_header("Access-Control-Allow-Methods", "POST, GET, PUT, DELETE, OPTIONS")
|
||||
self.set_header("Access-Control-Allow-Headers", "x-token, authorization, Authorization, Content-Type, Access-Control-Allow-Origin, Access-Control-Allow-Headers, X-Requested-By, Access-Control-Allow-Methods")
|
||||
self.set_header("Access-Control-Expose-Headers", "Cache-Control, Content-Language, Content-Type, Expires, Last-Modified, Pragma")
|
||||
# 同时定义一个option方法
|
||||
def options(self):
|
||||
self.set_status(204)
|
||||
self.finish()
|
||||
|
||||
@property
|
||||
def db(self):
|
||||
try:
|
||||
# check every time。
|
||||
self.application.db.query("SELECT 1 ")
|
||||
except Exception as e:
|
||||
print(e)
|
||||
self.application.db.reconnect()
|
||||
return self.application.db
|
||||
|
||||
class LeftMenu:
|
||||
def __init__(self, url):
|
||||
self.leftMenuList = stock_web_dic.STOCK_WEB_DATA_LIST
|
||||
self.current_url = url
|
||||
|
||||
# 获得左菜单。
|
||||
def GetLeftMenu(url):
|
||||
return LeftMenu(url)
|
||||
Executable
+50
@@ -0,0 +1,50 @@
|
||||
#!/usr/local/bin/python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
|
||||
from tornado import gen
|
||||
import libs.stock_web_dic as stock_web_dic
|
||||
import web.base as webBase
|
||||
import libs.common as common
|
||||
import logging
|
||||
import tornado.web
|
||||
import matplotlib
|
||||
matplotlib.use('Agg')
|
||||
import matplotlib.pyplot as plt
|
||||
import numpy as np
|
||||
import io
|
||||
|
||||
def GenImage(freq):
|
||||
t = np.linspace(0, 10, 500)
|
||||
y = np.sin(t * freq * 2 * 3.141)
|
||||
fig1 = plt.figure()
|
||||
plt.plot(t, y)
|
||||
plt.xlabel('Time [s]')
|
||||
memdata = io.BytesIO()
|
||||
plt.grid(True)
|
||||
plt.savefig(memdata, format='png')
|
||||
image = memdata.getvalue()
|
||||
return image
|
||||
|
||||
|
||||
class ImageHandler(tornado.web.RequestHandler):
|
||||
@gen.coroutine
|
||||
def get(self):
|
||||
image = GenImage(0.5)
|
||||
self.set_header('Content-type', 'image/png')
|
||||
self.set_header('Content-length', len(image))
|
||||
self.write(image)
|
||||
|
||||
# 获得页面数据。
|
||||
class GetChartHtmlHandler(webBase.BaseHandler):
|
||||
@gen.coroutine
|
||||
def get(self):
|
||||
name = self.get_argument("table_name", default=None, strip=False)
|
||||
#stockWeb = stock_web_dic.STOCK_WEB_DATA_MAP[name]
|
||||
# self.uri_ = ("self.request.url:", self.request.uri)
|
||||
# print self.uri_
|
||||
logging.info("chart...")
|
||||
self.render("stock_chart.html", entries="",
|
||||
pythonStockVersion=common.__version__,
|
||||
leftMenu=webBase.GetLeftMenu(self.request.uri))
|
||||
|
||||
Executable
+110
@@ -0,0 +1,110 @@
|
||||
#!/usr/local/bin/python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
|
||||
from tornado import gen
|
||||
# import sys
|
||||
# import os
|
||||
# sys.path.append(os.path.abspath('/data/stock/libs'))
|
||||
import libs.stock_web_dic as stock_web_dic
|
||||
import web.base as webBase
|
||||
import libs.common as common
|
||||
import logging
|
||||
import re
|
||||
|
||||
# 获得页面数据。
|
||||
class GetEditorHtmlHandler(webBase.BaseHandler):
|
||||
@gen.coroutine
|
||||
def get(self):
|
||||
name = self.get_argument("table_name", default=None, strip=False)
|
||||
stockWeb = stock_web_dic.STOCK_WEB_DATA_MAP[name]
|
||||
# self.uri_ = ("self.request.url:", self.request.uri)
|
||||
# print self.uri_
|
||||
self.render("data_editor.html", stockWeb=stockWeb,
|
||||
pythonStockVersion=common.__version__,
|
||||
leftMenu=webBase.GetLeftMenu(self.request.uri))
|
||||
|
||||
|
||||
# 拼接sql,将value的key 和 value 放到一起。
|
||||
def genSql(primary_key, param_map, join_string):
|
||||
tmp_sql = ""
|
||||
idx = 0
|
||||
for tmp_key in primary_key:
|
||||
tmp_val = param_map[tmp_key]
|
||||
if idx == 0:
|
||||
tmp_sql = " `%s` = '%s' " % (tmp_key, tmp_val)
|
||||
else:
|
||||
tmp_sql += join_string + (" `%s` = '%s' " % (tmp_key, tmp_val))
|
||||
idx += 1
|
||||
return tmp_sql
|
||||
|
||||
|
||||
# 获得页面数据。
|
||||
class SaveEditorHandler(webBase.BaseHandler):
|
||||
@gen.coroutine
|
||||
def post(self):
|
||||
action = self.get_argument("action", default=None, strip=False)
|
||||
logging.info(action)
|
||||
table_name = self.get_argument("table_name", default=None, strip=False)
|
||||
stockWeb = stock_web_dic.STOCK_WEB_DATA_MAP[table_name]
|
||||
# 临时map数组。
|
||||
param_map = {}
|
||||
# 支持多排序。使用shift+鼠标左键。
|
||||
for item, val in self.request.arguments.items():
|
||||
# 正则查找 data[1112][code] 里面的code字段
|
||||
item_key = re.search(r"\]\[(.*?)\]", item)
|
||||
if item_key:
|
||||
tmp_1 = item_key.group()
|
||||
if tmp_1:
|
||||
tmp_1 = tmp_1.replace("][", "").replace("]", "")
|
||||
param_map[tmp_1] = val[0].decode("utf-8")
|
||||
#logging.info(param_map)
|
||||
if action == "create":
|
||||
logging.info("###########################create")
|
||||
# 拼接where 和 update 语句。
|
||||
tmp_columns = "`, `".join(stockWeb.columns)
|
||||
tmp_values = []
|
||||
for tmp_key in stockWeb.columns:
|
||||
tmp_values.append(param_map[tmp_key])
|
||||
# 更新sql。
|
||||
tmp_values2 = "', '".join(tmp_values)
|
||||
insert_sql = " INSERT INTO %s (`%s`) VALUES('%s'); " % (stockWeb.table_name, tmp_columns, tmp_values2)
|
||||
logging.info(insert_sql)
|
||||
try:
|
||||
self.db.execute(insert_sql)
|
||||
except Exception as e:
|
||||
err = {"error": str(e)}
|
||||
logging.info(err)
|
||||
self.write(err)
|
||||
return
|
||||
|
||||
elif action == "edit":
|
||||
logging.info("###########################edit")
|
||||
# 拼接where 和 update 语句。
|
||||
tmp_update = genSql(stockWeb.columns, param_map, ",")
|
||||
tmp_where = genSql(stockWeb.primary_key, param_map, "and")
|
||||
# 更新sql。
|
||||
update_sql = " UPDATE %s SET %s WHERE %s " % (stockWeb.table_name, tmp_update, tmp_where)
|
||||
logging.info(update_sql)
|
||||
try:
|
||||
self.db.execute(update_sql)
|
||||
except Exception as e:
|
||||
err = {"error": str(e)}
|
||||
logging.info(err)
|
||||
self.write(err)
|
||||
return
|
||||
elif action == "remove":
|
||||
logging.info("###########################remove")
|
||||
# 拼接where 语句。
|
||||
tmp_where = genSql(stockWeb.primary_key, param_map, "and")
|
||||
# 更新sql。
|
||||
delete_sql = " DELETE FROM %s WHERE %s " % (stockWeb.table_name, tmp_where)
|
||||
logging.info(delete_sql)
|
||||
try:
|
||||
self.db.execute(delete_sql)
|
||||
except Exception as e:
|
||||
err = {"error": str(e)}
|
||||
logging.info(err)
|
||||
self.write(err)
|
||||
return
|
||||
self.write("{\"data\":[{}]}")
|
||||
Executable
+353
@@ -0,0 +1,353 @@
|
||||
#!/usr/local/bin/python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from tornado import gen
|
||||
import web.base as webBase
|
||||
import logging
|
||||
|
||||
# 首映 bokeh 画图。
|
||||
from bokeh.plotting import figure
|
||||
from bokeh.embed import components
|
||||
import datetime
|
||||
import libs.common as common
|
||||
import stockstats
|
||||
import numpy as np
|
||||
import pandas as pd
|
||||
from bokeh.layouts import gridplot
|
||||
from bokeh.palettes import Category20
|
||||
from math import radians
|
||||
from bokeh.models import DatetimeTickFormatter
|
||||
|
||||
|
||||
# 获得页面数据。
|
||||
class GetDataIndicatorsHandler(webBase.BaseHandler):
|
||||
@gen.coroutine
|
||||
def get(self):
|
||||
code = self.get_argument("code", default=None, strip=False)
|
||||
logging.info(code)
|
||||
# self.uri_ = ("self.request.url:", self.request.uri)
|
||||
# print self.uri_
|
||||
comp_list = []
|
||||
|
||||
try:
|
||||
date_now = datetime.datetime.now()
|
||||
date_end = date_now.strftime("%Y-%m-%d")
|
||||
date_start = (date_now + datetime.timedelta(days=-100)).strftime("%Y-%m-%d")
|
||||
print(code, date_start, date_end)
|
||||
|
||||
# open, high, close, low, volume, price_change, p_change, ma5, ma10, ma20, v_ma5, v_ma10, v_ma20, turnover
|
||||
# 使用缓存方法。加快计算速度。
|
||||
stock = common.get_hist_data_cache(code, date_start, date_end)
|
||||
logging.info(stock.head(1))
|
||||
|
||||
# print(stock) [186 rows x 14 columns]
|
||||
# 初始化统计类
|
||||
# stockStat = stockstats.StockDataFrame.retype(pd.read_csv("002032.csv"))
|
||||
stockStat = stockstats.StockDataFrame.retype(stock)
|
||||
batch_add(comp_list, stockStat)
|
||||
|
||||
|
||||
except Exception as e:
|
||||
logging.info("error :", e)
|
||||
logging.info("#################### GetStockHtmlHandlerEnd ####################")
|
||||
|
||||
self.render("stock_indicators.html", comp_list=comp_list,
|
||||
pythonStockVersion=common.__version__,
|
||||
leftMenu=webBase.GetLeftMenu(self.request.uri))
|
||||
|
||||
# 全部指标数据汇总
|
||||
indicators_all_dic = [
|
||||
{
|
||||
"title": "1,交易量delta指标分析",
|
||||
"desc": "The Volume Delta (Vol ∆) ",
|
||||
"dic": ["volume", "volume_delta"]
|
||||
}, {
|
||||
"title": "2,计算n天差",
|
||||
"desc": "可以计算,向前n天,和向后n天的差。",
|
||||
"dic": ["close", "close_1_d", "close_2_d", "close_-1_d", "close_-2_d"]
|
||||
}, {
|
||||
"title": "3,n天涨跌百分百计算",
|
||||
"desc": "可以看到,-n天数据和今天数据的百分比。",
|
||||
"dic": ["close", "close_-1_r", "close_-2_r"]
|
||||
}, {
|
||||
"title": "4,CR指标",
|
||||
"desc": """
|
||||
http://wiki.mbalib.com/wiki/CR%E6%8C%87%E6%A0%87 价格动量指标
|
||||
4. CR跌穿a、b、c、d四条线,再由低点向上爬升160时,为短线获利的一个良机,应适当卖出股票。
|
||||
5. CR跌至40以下时,是建仓良机。而CR高于300~400时,应注意适当减仓。
|
||||
""",
|
||||
"dic": ["close","cr","cr-ma1","cr-ma2","cr-ma3"]
|
||||
}, {
|
||||
"title": "5,最大值,最小值",
|
||||
"desc": """
|
||||
计算区间最大值
|
||||
volume max of three days ago, yesterday and two days later
|
||||
stock["volume_-3,2,-1_max"]
|
||||
volume min between 3 days ago and tomorrow
|
||||
stock["volume_-3~1_min"]
|
||||
实际使用的时候使用 -2~2 可计算出5天的最大,最小值。
|
||||
""",
|
||||
"dic": ["volume","volume_-2~2_max","volume_-2~2_min"]
|
||||
}, {
|
||||
"title": "6,KDJ指标",
|
||||
"desc": """
|
||||
http://wiki.mbalib.com/wiki/%E9%9A%8F%E6%9C%BA%E6%8C%87%E6%A0%87
|
||||
随机指标(KDJ)一般是根据统计学的原理,通过一个特定的周期(常为9日、9周等)内出现过的最高价、最低价及最后一个计算周期的收盘价及这三者之间的比例关系,来计算最后一个计算周期的未成熟随机值RSV,然后根据平滑移动平均线的方法来计算K值、D值与J值,并绘成曲线图来研判股票走势。
|
||||
(3)在使用中,常有J线的指标,即3乘以K值减2乘以D值(3K-2D=J),其目的是求出K值与D值的最大乖离程度,以领先KD值找出底部和头部。J大于100时为超买,小于10时为超卖。
|
||||
""",
|
||||
"dic": ["close","kdjk","kdjd","kdjj"]
|
||||
}, {
|
||||
"title": "7,SMA指标",
|
||||
"desc": """
|
||||
http://wiki.mbalib.com/wiki/Sma
|
||||
简单移动平均线(Simple Moving Average,SMA)
|
||||
可以动态输入参数,获得几天的移动平均。
|
||||
""",
|
||||
"dic": ["close","close_5_sma","close_10_sma"]
|
||||
}, {
|
||||
"title": "8,MACD指标",
|
||||
"desc": """
|
||||
http://wiki.mbalib.com/wiki/MACD
|
||||
平滑异同移动平均线(Moving Average Convergence Divergence,简称MACD指标),也称移动平均聚散指标
|
||||
MACD
|
||||
stock["macd"]
|
||||
MACD signal line
|
||||
stock["macds"]
|
||||
MACD histogram
|
||||
stock["macdh"]
|
||||
MACD技术分析,运用DIF线与MACD线之相交型态及直线棒高低点与背离现象,作为买卖讯号,尤其当市场股价走势呈一较为明确波段趋势时,
|
||||
MACD 则可发挥其应有的功能,但当市场呈牛皮盘整格局,股价不上不下时,MACD买卖讯号较不明显。
|
||||
当用MACD作分析时,亦可运用其他的技术分析指标如短期 K,D图形作为辅助工具,而且也可对买卖讯号作双重的确认。
|
||||
""",
|
||||
"dic": ["close","macd","macds","macdh"]
|
||||
}, {
|
||||
"title": "9,BOLL指标",
|
||||
"desc": """
|
||||
http://wiki.mbalib.com/wiki/BOLL
|
||||
布林线指标(Bollinger Bands)
|
||||
bolling, including upper band and lower band
|
||||
stock["boll"]
|
||||
stock["boll_ub"]
|
||||
stock["boll_lb"]
|
||||
1、当布林线开口向上后,只要股价K线始终运行在布林线的中轨上方的时候,说明股价一直处在一个中长期上升轨道之中,这是BOLL指标发出的持股待涨信号,如果TRIX指标也是发出持股信号时,这种信号更加准确。此时,投资者应坚决持股待涨。
|
||||
2、当布林线开口向下后,只要股价K线始终运行在布林线的中轨下方的时候,说明股价一直处在一个中长期下降轨道之中,这是BOLL指标发出的持币观望信号,如果TRIX指标也是发出持币信号时,这种信号更加准确。此时,投资者应坚决持币观望。
|
||||
""",
|
||||
"dic": ["close","boll","boll_ub","boll_lb"]
|
||||
}, {
|
||||
"title": "10,RSI指标",
|
||||
"desc": """
|
||||
http://wiki.mbalib.com/wiki/RSI
|
||||
相对强弱指标(Relative Strength Index,简称RSI),也称相对强弱指数、相对力度指数
|
||||
6 days RSI
|
||||
stock["rsi_6"]
|
||||
12 days RSI
|
||||
stock["rsi_12"]
|
||||
(2)强弱指标保持高于50表示为强势市场,反之低于50表示为弱势市场。
|
||||
(3)强弱指标多在70与30之间波动。当六日指标上升到达80时,表示股市已有超买现象,如果一旦继续上升,超过90以上时,则表示已到严重超买的警戒区,股价已形成头部,极可能在短期内反转回转。
|
||||
(4)当六日强弱指标下降至20时,表示股市有超卖现象,如果一旦继续下降至10以下时则表示已到严重超卖区域,股价极可能有止跌回升的机会。
|
||||
""",
|
||||
"dic": ["close","rsi_6","rsi_12"]
|
||||
}, {
|
||||
"title": "11,WR指标",
|
||||
"desc": """
|
||||
http://wiki.mbalib.com/wiki/%E5%A8%81%E5%BB%89%E6%8C%87%E6%A0%87
|
||||
威廉指数(Williams%Rate)该指数是利用摆动点来度量市场的超买超卖现象。
|
||||
10 days WR
|
||||
stock["wr_10"]
|
||||
6 days WR
|
||||
stock["wr_6"]
|
||||
""",
|
||||
"dic": ["close","wr_10","wr_6"]
|
||||
}, {
|
||||
"title": "12,CCI指标",
|
||||
"desc": """
|
||||
http://wiki.mbalib.com/wiki/%E9%A1%BA%E5%8A%BF%E6%8C%87%E6%A0%87
|
||||
顺势指标又叫CCI指标,其英文全称为“Commodity Channel Index”,
|
||||
是由美国股市分析家唐纳德·蓝伯特(Donald Lambert)所创造的,是一种重点研判股价偏离度的股市分析工具。
|
||||
CCI, default to 14 days
|
||||
stock["cci"]
|
||||
20 days CCI
|
||||
stock["cci_20"]
|
||||
1、当CCI指标从下向上突破﹢100线而进入非常态区间时,表明股价脱离常态而进入异常波动阶段,
|
||||
中短线应及时买入,如果有比较大的成交量配合,买入信号则更为可靠。
|
||||
2、当CCI指标从上向下突破﹣100线而进入另一个非常态区间时,表明股价的盘整阶段已经结束,
|
||||
将进入一个比较长的寻底过程,投资者应以持币观望为主。
|
||||
""",
|
||||
"dic": ["close","cci","cci_20"]
|
||||
}, {
|
||||
"title": "13,TR、ATR指标",
|
||||
"desc": """
|
||||
http://wiki.mbalib.com/wiki/%E5%9D%87%E5%B9%85%E6%8C%87%E6%A0%87
|
||||
均幅指标(Average True Ranger,ATR)
|
||||
均幅指标(ATR)是取一定时间周期内的股价波动幅度的移动平均值,主要用于研判买卖时机。
|
||||
TR (true range)
|
||||
stock["tr"]
|
||||
ATR (Average True Range)
|
||||
stock["atr"]
|
||||
均幅指标无论是从下向上穿越移动平均线,还是从上向下穿越移动平均线时,都是一种研判信号。
|
||||
""",
|
||||
"dic": ["close","tr","atr"]
|
||||
}, {
|
||||
"title": "14,DMA指标",
|
||||
"desc": """
|
||||
http://wiki.mbalib.com/wiki/DMA
|
||||
DMA指标(Different of Moving Average)又叫平行线差指标,是目前股市分析技术指标中的一种中短期指标,它常用于大盘指数和个股的研判。
|
||||
DMA, difference of 10 and 50 moving average
|
||||
stock["dma"]
|
||||
""",
|
||||
"dic": ["close","dma"]
|
||||
}, {
|
||||
"title": "15,DMI,+DI,-DI,DX,ADX,ADXR指标",
|
||||
"desc": """
|
||||
http://wiki.mbalib.com/wiki/DMI
|
||||
动向指数Directional Movement Index,DMI)
|
||||
http://wiki.mbalib.com/wiki/ADX
|
||||
平均趋向指标(Average Directional Indicator,简称ADX)
|
||||
http://wiki.mbalib.com/wiki/%E5%B9%B3%E5%9D%87%E6%96%B9%E5%90%91%E6%8C%87%E6%95%B0%E8%AF%84%E4%BC%B0
|
||||
平均方向指数评估(ADXR)实际是今日ADX与前面某一日的ADX的平均值。ADXR在高位与ADX同步下滑,可以增加对ADX已经调头的尽早确认。
|
||||
ADXR是ADX的附属产品,只能发出一种辅助和肯定的讯号,并非入市的指标,而只需同时配合动向指标(DMI)的趋势才可作出买卖策略。
|
||||
在应用时,应以ADX为主,ADXR为辅。
|
||||
""",
|
||||
"dic": ["close","pdi","mdi","dx","adx","adxr"]
|
||||
}, {
|
||||
"title": "16,TRIX,MATRIX指标",
|
||||
"desc": """
|
||||
http://wiki.mbalib.com/wiki/TRIX
|
||||
TRIX指标又叫三重指数平滑移动平均指标(Triple Exponentially Smoothed Average)
|
||||
""",
|
||||
"dic": ["close","trix","trix_9_sma"]
|
||||
}, {
|
||||
"title": "17,VR,MAVR指标",
|
||||
"desc": """
|
||||
http://wiki.mbalib.com/wiki/%E6%88%90%E4%BA%A4%E9%87%8F%E6%AF%94%E7%8E%87
|
||||
成交量比率(Volumn Ratio,VR)(简称VR),是一项通过分析股价上升日成交额(或成交量,下同)与股价下降日成交额比值,
|
||||
从而掌握市场买卖气势的中期技术指标。
|
||||
VR, default to 26 days
|
||||
stock["vr"]
|
||||
MAVR is the simple moving average of VR
|
||||
stock["vr_6_sma"]
|
||||
""",
|
||||
"dic": ["close","vr","vr_6_sma"]
|
||||
}
|
||||
]
|
||||
# 配置数据
|
||||
indicators_dic = [
|
||||
{
|
||||
"title": "6,KDJ指标",
|
||||
"desc": """
|
||||
http://wiki.mbalib.com/wiki/%E9%9A%8F%E6%9C%BA%E6%8C%87%E6%A0%87
|
||||
随机指标(KDJ)一般是根据统计学的原理,通过一个特定的周期(常为9日、9周等)内出现过的最高价、最低价及最后一个计算周期的收盘价及这三者之间的比例关系,来计算最后一个计算周期的未成熟随机值RSV,然后根据平滑移动平均线的方法来计算K值、D值与J值,并绘成曲线图来研判股票走势。
|
||||
(3)在使用中,常有J线的指标,即3乘以K值减2乘以D值(3K-2D=J),其目的是求出K值与D值的最大乖离程度,以领先KD值找出底部和头部。J大于100时为超买,小于10时为超卖。
|
||||
""",
|
||||
"dic": ["close","kdjk","kdjd","kdjj"]
|
||||
}, {
|
||||
"title": "7,SMA指标",
|
||||
"desc": """
|
||||
http://wiki.mbalib.com/wiki/Sma
|
||||
简单移动平均线(Simple Moving Average,SMA)
|
||||
可以动态输入参数,获得几天的移动平均。
|
||||
""",
|
||||
"dic": ["close","close_5_sma","close_10_sma"]
|
||||
}, {
|
||||
"title": "8,MACD指标",
|
||||
"desc": """
|
||||
http://wiki.mbalib.com/wiki/MACD
|
||||
平滑异同移动平均线(Moving Average Convergence Divergence,简称MACD指标),也称移动平均聚散指标
|
||||
MACD
|
||||
stock["macd"]
|
||||
MACD signal line
|
||||
stock["macds"]
|
||||
MACD histogram
|
||||
stock["macdh"]
|
||||
MACD技术分析,运用DIF线与MACD线之相交型态及直线棒高低点与背离现象,作为买卖讯号,尤其当市场股价走势呈一较为明确波段趋势时,
|
||||
MACD 则可发挥其应有的功能,但当市场呈牛皮盘整格局,股价不上不下时,MACD买卖讯号较不明显。
|
||||
当用MACD作分析时,亦可运用其他的技术分析指标如短期 K,D图形作为辅助工具,而且也可对买卖讯号作双重的确认。
|
||||
""",
|
||||
"dic": ["close","macd","macds","macdh"]
|
||||
}, {
|
||||
"title": "9,BOLL指标",
|
||||
"desc": """
|
||||
http://wiki.mbalib.com/wiki/BOLL
|
||||
布林线指标(Bollinger Bands)
|
||||
bolling, including upper band and lower band
|
||||
stock["boll"]
|
||||
stock["boll_ub"]
|
||||
stock["boll_lb"]
|
||||
1、当布林线开口向上后,只要股价K线始终运行在布林线的中轨上方的时候,说明股价一直处在一个中长期上升轨道之中,这是BOLL指标发出的持股待涨信号,如果TRIX指标也是发出持股信号时,这种信号更加准确。此时,投资者应坚决持股待涨。
|
||||
2、当布林线开口向下后,只要股价K线始终运行在布林线的中轨下方的时候,说明股价一直处在一个中长期下降轨道之中,这是BOLL指标发出的持币观望信号,如果TRIX指标也是发出持币信号时,这种信号更加准确。此时,投资者应坚决持币观望。
|
||||
""",
|
||||
"dic": ["close","boll","boll_ub","boll_lb"]
|
||||
}, {
|
||||
"title": "10,RSI指标",
|
||||
"desc": """
|
||||
http://wiki.mbalib.com/wiki/RSI
|
||||
相对强弱指标(Relative Strength Index,简称RSI),也称相对强弱指数、相对力度指数
|
||||
6 days RSI
|
||||
stock["rsi_6"]
|
||||
12 days RSI
|
||||
stock["rsi_12"]
|
||||
(2)强弱指标保持高于50表示为强势市场,反之低于50表示为弱势市场。
|
||||
(3)强弱指标多在70与30之间波动。当六日指标上升到达80时,表示股市已有超买现象,如果一旦继续上升,超过90以上时,则表示已到严重超买的警戒区,股价已形成头部,极可能在短期内反转回转。
|
||||
(4)当六日强弱指标下降至20时,表示股市有超卖现象,如果一旦继续下降至10以下时则表示已到严重超卖区域,股价极可能有止跌回升的机会。
|
||||
""",
|
||||
"dic": ["close","rsi_6","rsi_12"]
|
||||
},{
|
||||
"title": "12,CCI指标",
|
||||
"desc": """
|
||||
http://wiki.mbalib.com/wiki/%E9%A1%BA%E5%8A%BF%E6%8C%87%E6%A0%87
|
||||
顺势指标又叫CCI指标,其英文全称为“Commodity Channel Index”,
|
||||
是由美国股市分析家唐纳德·蓝伯特(Donald Lambert)所创造的,是一种重点研判股价偏离度的股市分析工具。
|
||||
CCI, default to 14 days
|
||||
stock["cci"]
|
||||
20 days CCI
|
||||
stock["cci_20"]
|
||||
1、当CCI指标从下向上突破﹢100线而进入非常态区间时,表明股价脱离常态而进入异常波动阶段,
|
||||
中短线应及时买入,如果有比较大的成交量配合,买入信号则更为可靠。
|
||||
2、当CCI指标从上向下突破﹣100线而进入另一个非常态区间时,表明股价的盘整阶段已经结束,
|
||||
将进入一个比较长的寻底过程,投资者应以持币观望为主。
|
||||
""",
|
||||
"dic": ["close","cci","cci_20"]
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
# 批量添加数据。
|
||||
def batch_add(comp_list, stockStat):
|
||||
for conf in indicators_dic:
|
||||
logging.info(conf)
|
||||
|
||||
comp_list.append(add_plot(stockStat, conf))
|
||||
|
||||
|
||||
# 增加画图方法
|
||||
def add_plot(stockStat, conf):
|
||||
p_list = []
|
||||
logging.info("############################", type(conf["dic"]))
|
||||
# 循环 多个line 信息。
|
||||
for key, val in enumerate(conf["dic"]):
|
||||
logging.info(key)
|
||||
logging.info(val)
|
||||
|
||||
p1 = figure(width=1000, height=150, x_axis_type="datetime")
|
||||
# add renderers
|
||||
stockStat["date"] = pd.to_datetime(stockStat.index.values)
|
||||
# ["volume","volume_delta"]
|
||||
# 设置20个颜色循环,显示0 2 4 6 号序列。
|
||||
p1.line(stockStat["date"], stockStat[val], color=Category20[20][key * 2])
|
||||
|
||||
# Set date format for x axis 格式化。
|
||||
p1.xaxis.formatter = DatetimeTickFormatter(
|
||||
hours=["%Y-%m-%d"], days=["%Y-%m-%d"],
|
||||
months=["%Y-%m-%d"], years=["%Y-%m-%d"])
|
||||
# p1.xaxis.major_label_orientation = radians(30) #可以旋转一个角度。
|
||||
|
||||
p_list.append([p1])
|
||||
|
||||
gp = gridplot(p_list)
|
||||
script, div = components(gp)
|
||||
return {
|
||||
"script": script,
|
||||
"div": div,
|
||||
"title": conf["title"],
|
||||
"desc": conf["desc"]
|
||||
}
|
||||
Executable
+224
@@ -0,0 +1,224 @@
|
||||
#!/usr/local/bin/python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import json
|
||||
from tornado import gen
|
||||
import libs.common as common
|
||||
import libs.stock_web_dic as stock_web_dic
|
||||
import web.base as webBase
|
||||
import logging
|
||||
import datetime
|
||||
|
||||
# info 蓝色 云财经
|
||||
# success 绿色
|
||||
# danger 红色 东方财富
|
||||
# warning 黄色
|
||||
WEB_EASTMONEY_URL = u"""
|
||||
<a class='btn btn-danger btn-xs tooltip-danger' data-rel="tooltip" data-placement="right" data-original-title="东方财富,股票详细地址,新窗口跳转。"
|
||||
href='http://quote.eastmoney.com/%s.html' target='_blank'>东财</a>
|
||||
|
||||
<a class='btn btn-success btn-xs tooltip-success' data-rel="tooltip" data-placement="right" data-original-title="本地MACD,KDJ等指标,本地弹窗窗口,数据加载中,请稍候。"
|
||||
onclick="showIndicatorsWindow('%s');">指标</a>
|
||||
|
||||
<a class='btn btn-warning btn-xs tooltip-warning' data-rel="tooltip" data-placement="right" data-original-title="东方财富,研报地址,本地弹窗窗口。"
|
||||
onclick="showDFCFWindow('%s');">东研</a>
|
||||
|
||||
|
||||
"""
|
||||
# 和在dic中的字符串一致。字符串前面都不特别声明是u""
|
||||
eastmoney_name = "查看股票"
|
||||
|
||||
|
||||
# 获得页面数据,进入页面中。
|
||||
class GetStockHtmlHandler(webBase.BaseHandler):
|
||||
@gen.coroutine
|
||||
def get(self):
|
||||
name = self.get_argument("table_name", default=None, strip=False)
|
||||
tableInfo = stock_web_dic.STOCK_WEB_DATA_MAP[name]
|
||||
# self.uri_ = ("self.request.url:", self.request.uri)
|
||||
# print self.uri_
|
||||
date_now = datetime.datetime.now()
|
||||
date_now_str = date_now.strftime("%Y%m%d")
|
||||
# 每天的 16 点前显示昨天数据。
|
||||
if date_now.hour < 16:
|
||||
date_now_str = (date_now + datetime.timedelta(days=-1)).strftime("%Y%m%d")
|
||||
|
||||
# try:
|
||||
# # 增加columns 字段中的【查看股票 东方财富】
|
||||
# logging.info(eastmoney_name in tableInfo.column_names)
|
||||
# if eastmoney_name in tableInfo.column_names:
|
||||
# tmp_idx = tableInfo.column_names.index(eastmoney_name)
|
||||
# logging.info(tmp_idx)
|
||||
# try:
|
||||
# # 防止重复插入数据。可能会报错。
|
||||
# tableInfo.columns.remove("eastmoney_url")
|
||||
# except Exception as e:
|
||||
# print("error :", e)
|
||||
# tableInfo.columns.insert(tmp_idx, "eastmoney_url")
|
||||
# except Exception as e:
|
||||
# print("error :", e)
|
||||
logging.info("####################GetStockHtmlHandlerEnd")
|
||||
self.render("tableInfo.html", tableInfo=tableInfo, date_now=date_now_str,
|
||||
pythonStockVersion=common.__version__,
|
||||
leftMenu=webBase.GetLeftMenu(self.request.uri))
|
||||
|
||||
|
||||
# 获得股票数据内容。
|
||||
class GetStockDataHandler(webBase.BaseHandler):
|
||||
def get(self):
|
||||
|
||||
self.set_header('Content-Type', 'application/json;charset=UTF-8')
|
||||
|
||||
logging.info("######################## GetStockDataHandler ########################")
|
||||
# 获得分页参数。
|
||||
page_param = self.get_argument("page", default=0, strip=False)
|
||||
limit_param = self.get_argument("limit", default=10, strip=False)
|
||||
|
||||
name_param = self.get_argument("name", default="stock_zh_ah_name", strip=False)
|
||||
type_param = self.get_argument("type", default=None, strip=False)
|
||||
date_param = self.get_argument("date", default=None, strip=False)
|
||||
code_param = self.get_argument("code", default=None, strip=False)
|
||||
|
||||
logging.info(f"page param: {page_param}, {limit_param}, {type_param}, {date_param}, {code_param}")
|
||||
|
||||
|
||||
if name_param == ":tableName":
|
||||
obj = {
|
||||
"code": 20000,
|
||||
"message": "success",
|
||||
"draw": 0,
|
||||
"data": []
|
||||
}
|
||||
# logging.info("####################")
|
||||
# logging.info(obj)
|
||||
self.write(json.dumps(obj))
|
||||
return
|
||||
|
||||
|
||||
tableInfo = stock_web_dic.STOCK_WEB_DATA_MAP[name_param]
|
||||
|
||||
|
||||
order_by_column = []
|
||||
order_by_dir = []
|
||||
# 支持多排序。使用shift+鼠标左键。
|
||||
for item, val in self.request.arguments.items():
|
||||
# logging.info("item: %s, val: %s" % (item, val) )
|
||||
if str(item).startswith("order["):
|
||||
print("order:", item, ",val:", val[0])
|
||||
if str(item).startswith("order[") and str(item).endswith("[column]"):
|
||||
order_by_column.append(int(val[0]))
|
||||
if str(item).startswith("order[") and str(item).endswith("[dir]"):
|
||||
order_by_dir.append(val[0].decode("utf-8")) # bytes转换字符串
|
||||
|
||||
search_by_column = []
|
||||
search_by_data = []
|
||||
|
||||
# 返回search字段。
|
||||
for item, val in self.request.arguments.items():
|
||||
# logging.info("item: %s, val: %s" % (item, val))
|
||||
if str(item).startswith("columns[") and str(item).endswith("[search][value]"):
|
||||
logging.info("item: %s, val: %s" % (item, val))
|
||||
str_idx = item.replace("columns[", "").replace("][search][value]", "")
|
||||
int_idx = int(str_idx)
|
||||
# 找到字符串
|
||||
str_val = val[0].decode("utf-8")
|
||||
if str_val != "": # 字符串。
|
||||
search_by_column.append(tableInfo.columns[int_idx])
|
||||
search_by_data.append(val[0].decode("utf-8")) # bytes转换字符串
|
||||
|
||||
# 打印日志。
|
||||
search_sql = ""
|
||||
search_idx = 0
|
||||
|
||||
logging.info("################# search_by_column #################")
|
||||
|
||||
logging.info(search_by_column)
|
||||
logging.info(search_by_data)
|
||||
for item in search_by_column:
|
||||
val = search_by_data[search_idx]
|
||||
logging.info("idx: %s, column: %s, value: %s " % (search_idx, item, val))
|
||||
# 查询sql
|
||||
if search_idx == 0:
|
||||
search_sql = " WHERE `%s` = '%s' " % (item, val)
|
||||
else:
|
||||
search_sql = search_sql + " AND `%s` = '%s' " % (item, val)
|
||||
search_idx = search_idx + 1
|
||||
|
||||
if date_param:
|
||||
if "WHERE" not in search_sql:
|
||||
search_sql += f" WHERE `date` = '{date_param}' "
|
||||
else:
|
||||
search_sql += f" AND `date` = '{date_param}' "
|
||||
|
||||
if code_param:
|
||||
if "WHERE" not in search_sql:
|
||||
search_sql += f" WHERE `code` = '{code_param}' "
|
||||
else:
|
||||
search_sql += f" AND `code` = '{code_param}' "
|
||||
|
||||
# print("tableInfo :", stock_web)
|
||||
order_by_sql = ""
|
||||
# 增加排序。
|
||||
if len(order_by_column) != 0 and len(order_by_dir) != 0:
|
||||
order_by_sql = " ORDER BY "
|
||||
idx = 0
|
||||
for key in order_by_column:
|
||||
# 找到排序字段和dir。
|
||||
col_tmp = tableInfo.columns[key]
|
||||
dir_tmp = order_by_dir[idx]
|
||||
if idx != 0:
|
||||
order_by_sql += " , %s %s" % (col_tmp, dir_tmp)
|
||||
else:
|
||||
order_by_sql += " %s %s" % (col_tmp, dir_tmp)
|
||||
idx += 1
|
||||
# 查询数据库。
|
||||
limit_sql = ""
|
||||
if int(limit_param) > 0:
|
||||
start = ( int(page_param) - 1 ) * int(limit_param)
|
||||
limit_sql = f" LIMIT {start} , {limit_param} "
|
||||
sql = " SELECT * FROM `%s` %s %s %s " % (
|
||||
tableInfo.table_name, search_sql, order_by_sql, limit_sql)
|
||||
count_sql = " SELECT count(1) as num FROM `%s` %s " % (tableInfo.table_name, search_sql)
|
||||
|
||||
logging.info("select sql : " + sql)
|
||||
logging.info("count sql : " + count_sql)
|
||||
stock_web_list = self.db.query(sql)
|
||||
|
||||
stock_web_size = self.db.query(count_sql)
|
||||
logging.info("tableInfoList size : %s " % stock_web_size)
|
||||
|
||||
# 动态表格展示:
|
||||
table_columns = []
|
||||
try:
|
||||
tmp_len = len(tableInfo.columns)
|
||||
logging.info("ableInfo.columns tmp_len : %s " % tmp_len)
|
||||
# 循环数据,转换成对象,放入到数组中,方便前端 vue table 循环使用。
|
||||
for tmp_idx in range(0, tmp_len):
|
||||
logging.info(tmp_idx)
|
||||
|
||||
column = tableInfo.columns[tmp_idx]
|
||||
column_name = tableInfo.column_names[tmp_idx]
|
||||
|
||||
tpm_column_obj = {
|
||||
"column": column,
|
||||
"columnName" : column_name
|
||||
}
|
||||
table_columns.append(tpm_column_obj)
|
||||
|
||||
except Exception as e:
|
||||
print("error :", e)
|
||||
|
||||
obj = {
|
||||
"code": 20000,
|
||||
"message": "success",
|
||||
"draw": 0,
|
||||
"tableName" : tableInfo.name,
|
||||
"tableColumns": table_columns,
|
||||
"total": stock_web_size[0]["num"],
|
||||
"recordsTotal": stock_web_size[0]["num"],
|
||||
"recordsFiltered": stock_web_size[0]["num"],
|
||||
"data": stock_web_list
|
||||
}
|
||||
# logging.info("####################")
|
||||
# logging.info(obj)
|
||||
self.write(json.dumps(obj))
|
||||
@@ -0,0 +1,244 @@
|
||||
"""
|
||||
This example demonstrates how to embed matplotlib WebAgg interactive
|
||||
plotting in your own web application and framework. It is not
|
||||
necessary to do all this if you merely want to display a plot in a
|
||||
browser or use matplotlib's built-in Tornado-based server "on the
|
||||
side".
|
||||
|
||||
The framework being used must support web sockets.
|
||||
"""
|
||||
|
||||
import io
|
||||
|
||||
try:
|
||||
import tornado
|
||||
except ImportError:
|
||||
raise RuntimeError("This example requires tornado.")
|
||||
import tornado.web
|
||||
import tornado.httpserver
|
||||
import tornado.ioloop
|
||||
import tornado.websocket
|
||||
|
||||
from matplotlib.backends.backend_webagg_core import (
|
||||
FigureManagerWebAgg, new_figure_manager_given_figure)
|
||||
from matplotlib.figure import Figure
|
||||
|
||||
import numpy as np
|
||||
|
||||
import json
|
||||
|
||||
|
||||
def create_figure():
|
||||
"""
|
||||
Creates a simple example figure.
|
||||
"""
|
||||
fig = Figure()
|
||||
a = fig.add_subplot(111)
|
||||
t = np.arange(0.0, 3.0, 0.01)
|
||||
s = np.sin(2 * np.pi * t)
|
||||
a.plot(t, s)
|
||||
return fig
|
||||
|
||||
|
||||
# The following is the content of the web page. You would normally
|
||||
# generate this using some sort of template facility in your web
|
||||
# framework, but here we just use Python string formatting.
|
||||
html_content = """
|
||||
<html>
|
||||
<head>
|
||||
<!-- TODO: There should be a way to include all of the required javascript
|
||||
and CSS so matplotlib can add to the set in the future if it
|
||||
needs to. -->
|
||||
<link rel="stylesheet" href="_static/css/page.css" type="text/css">
|
||||
<link rel="stylesheet" href="_static/css/boilerplate.css" type="text/css" />
|
||||
<link rel="stylesheet" href="_static/css/fbm.css" type="text/css" />
|
||||
<link rel="stylesheet" href="_static/jquery/css/themes/base/jquery-ui.min.css" >
|
||||
<script src="_static/jquery/js/jquery-1.11.3.min.js"></script>
|
||||
<script src="_static/jquery/js/jquery-ui.min.js"></script>
|
||||
<script src="mpl.js"></script>
|
||||
|
||||
<script>
|
||||
/* This is a callback that is called when the user saves
|
||||
(downloads) a file. Its purpose is really to map from a
|
||||
figure and file format to a url in the application. */
|
||||
function ondownload(figure, format) {
|
||||
window.open('download.' + format, '_blank');
|
||||
};
|
||||
|
||||
$(document).ready(
|
||||
function() {
|
||||
/* It is up to the application to provide a websocket that the figure
|
||||
will use to communicate to the server. This websocket object can
|
||||
also be a "fake" websocket that underneath multiplexes messages
|
||||
from multiple figures, if necessary. */
|
||||
var websocket_type = mpl.get_websocket_type();
|
||||
var websocket = new websocket_type("%(ws_uri)sws");
|
||||
|
||||
// mpl.figure creates a new figure on the webpage.
|
||||
var fig = new mpl.figure(
|
||||
// A unique numeric identifier for the figure
|
||||
%(fig_id)s,
|
||||
// A websocket object (or something that behaves like one)
|
||||
websocket,
|
||||
// A function called when a file type is selected for download
|
||||
ondownload,
|
||||
// The HTML element in which to place the figure
|
||||
$('div#figure'));
|
||||
}
|
||||
);
|
||||
</script>
|
||||
|
||||
<title>matplotlib</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="figure">
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
"""
|
||||
|
||||
|
||||
class MyApplication(tornado.web.Application):
|
||||
class MainPage(tornado.web.RequestHandler):
|
||||
"""
|
||||
Serves the main HTML page.
|
||||
"""
|
||||
|
||||
def get(self):
|
||||
manager = self.application.manager
|
||||
ws_uri = "ws://{req.host}/".format(req=self.request)
|
||||
content = html_content % {
|
||||
"ws_uri": ws_uri, "fig_id": manager.num}
|
||||
self.write(content)
|
||||
|
||||
class MplJs(tornado.web.RequestHandler):
|
||||
"""
|
||||
Serves the generated matplotlib javascript file. The content
|
||||
is dynamically generated based on which toolbar functions the
|
||||
user has defined. Call `FigureManagerWebAgg` to get its
|
||||
content.
|
||||
"""
|
||||
|
||||
def get(self):
|
||||
self.set_header('Content-Type', 'application/javascript')
|
||||
js_content = FigureManagerWebAgg.get_javascript()
|
||||
|
||||
self.write(js_content)
|
||||
|
||||
class Download(tornado.web.RequestHandler):
|
||||
"""
|
||||
Handles downloading of the figure in various file formats.
|
||||
"""
|
||||
|
||||
def get(self, fmt):
|
||||
manager = self.application.manager
|
||||
|
||||
mimetypes = {
|
||||
'ps': 'application/postscript',
|
||||
'eps': 'application/postscript',
|
||||
'pdf': 'application/pdf',
|
||||
'svg': 'image/svg+xml',
|
||||
'png': 'image/png',
|
||||
'jpeg': 'image/jpeg',
|
||||
'tif': 'image/tiff',
|
||||
'emf': 'application/emf'
|
||||
}
|
||||
|
||||
self.set_header('Content-Type', mimetypes.get(fmt, 'binary'))
|
||||
|
||||
buff = io.BytesIO()
|
||||
manager.canvas.print_figure(buff, format=fmt)
|
||||
self.write(buff.getvalue())
|
||||
|
||||
class WebSocket(tornado.websocket.WebSocketHandler):
|
||||
"""
|
||||
A websocket for interactive communication between the plot in
|
||||
the browser and the server.
|
||||
|
||||
In addition to the methods required by tornado, it is required to
|
||||
have two callback methods:
|
||||
|
||||
- ``send_json(json_content)`` is called by matplotlib when
|
||||
it needs to send json to the browser. `json_content` is
|
||||
a JSON tree (Python dictionary), and it is the responsibility
|
||||
of this implementation to encode it as a string to send over
|
||||
the socket.
|
||||
|
||||
- ``send_binary(blob)`` is called to send binary image data
|
||||
to the browser.
|
||||
"""
|
||||
supports_binary = True
|
||||
|
||||
def open(self):
|
||||
# Register the websocket with the FigureManager.
|
||||
manager = self.application.manager
|
||||
manager.add_web_socket(self)
|
||||
if hasattr(self, 'set_nodelay'):
|
||||
self.set_nodelay(True)
|
||||
|
||||
def on_close(self):
|
||||
# When the socket is closed, deregister the websocket with
|
||||
# the FigureManager.
|
||||
manager = self.application.manager
|
||||
manager.remove_web_socket(self)
|
||||
|
||||
def on_message(self, message):
|
||||
# The 'supports_binary' message is relevant to the
|
||||
# websocket itself. The other messages get passed along
|
||||
# to matplotlib as-is.
|
||||
|
||||
# Every message has a "type" and a "figure_id".
|
||||
message = json.loads(message)
|
||||
if message['type'] == 'supports_binary':
|
||||
self.supports_binary = message['value']
|
||||
else:
|
||||
manager = self.application.manager
|
||||
manager.handle_json(message)
|
||||
|
||||
def send_json(self, content):
|
||||
self.write_message(json.dumps(content))
|
||||
|
||||
def send_binary(self, blob):
|
||||
if self.supports_binary:
|
||||
self.write_message(blob, binary=True)
|
||||
else:
|
||||
data_uri = "data:image/png;base64,{0}".format(
|
||||
blob.encode('base64').replace('\n', ''))
|
||||
self.write_message(data_uri)
|
||||
|
||||
def __init__(self, figure):
|
||||
self.figure = figure
|
||||
self.manager = new_figure_manager_given_figure(
|
||||
id(figure), figure)
|
||||
|
||||
super(MyApplication, self).__init__([
|
||||
# Static files for the CSS and JS
|
||||
(r'/_static/(.*)',
|
||||
tornado.web.StaticFileHandler,
|
||||
{'path': FigureManagerWebAgg.get_static_file_path()}),
|
||||
|
||||
# The page that contains all of the pieces
|
||||
('/', self.MainPage),
|
||||
|
||||
('/mpl.js', self.MplJs),
|
||||
|
||||
# Sends images and events to the browser, and receives
|
||||
# events from the browser
|
||||
('/ws', self.WebSocket),
|
||||
|
||||
# Handles the downloading (i.e., saving) of static images
|
||||
(r'/download.([a-z0-9.]+)', self.Download),
|
||||
], debug=True)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
figure = create_figure()
|
||||
application = MyApplication(figure)
|
||||
http_server = tornado.httpserver.HTTPServer(application)
|
||||
http_server.listen(9999)
|
||||
|
||||
print("http://127.0.0.1:9090/")
|
||||
print("Press Ctrl+C to quit")
|
||||
|
||||
tornado.ioloop.IOLoop.instance().start()
|
||||
Executable
+175
@@ -0,0 +1,175 @@
|
||||
#!/usr/local/bin/python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import os.path
|
||||
import torndb
|
||||
import tornado.escape
|
||||
from tornado import gen
|
||||
import tornado.httpserver
|
||||
import tornado.ioloop
|
||||
import tornado.options
|
||||
import libs.common as common
|
||||
import libs.stock_web_dic as stock_web_dic
|
||||
import web.dataTableHandler as dataTableHandler
|
||||
import web.dataEditorHandler as dataEditorHandler
|
||||
import web.dataIndicatorsHandler as dataIndicatorsHandler
|
||||
import web.base as webBase
|
||||
import pandas as pd
|
||||
import numpy as np
|
||||
import akshare as ak
|
||||
import bokeh as bh
|
||||
import sqlalchemy
|
||||
import json
|
||||
|
||||
class Application(tornado.web.Application):
|
||||
def __init__(self):
|
||||
handlers = [
|
||||
# 设置路由
|
||||
(r"/", HomeHandler),
|
||||
(r"/stock/", HomeHandler),
|
||||
(r"/api/v1/package_verison", PackageVersionHandler),# 包版本
|
||||
(r"/api/v1/menu_list", MenuListHandler), # 菜单接口
|
||||
(r"/test_akshare", TestHandler),# 测试页面,做写js 测试。
|
||||
(r"/test2", Test2Handler),# 测试页面,做写js 测试。
|
||||
# 使用datatable 展示报表数据模块。
|
||||
(r"/api/v1/api_data", dataTableHandler.GetStockDataHandler),
|
||||
(r"/stock/data", dataTableHandler.GetStockHtmlHandler),
|
||||
# 数据修改dataEditor。
|
||||
(r"/data/editor", dataEditorHandler.GetEditorHtmlHandler),
|
||||
(r"/data/editor/save", dataEditorHandler.SaveEditorHandler),
|
||||
# 获得股票指标数据。
|
||||
(r"/api/v1/data/indicators", dataIndicatorsHandler.GetDataIndicatorsHandler),
|
||||
]
|
||||
settings = dict( # 配置
|
||||
template_path=os.path.join(os.path.dirname(__file__), "templates"),
|
||||
static_path=os.path.join(os.path.dirname(__file__), "static"),
|
||||
xsrf_cookies=False, # True,
|
||||
# cookie加密
|
||||
cookie_secret="027bb1b670eddf0392cdda8709268a17b58b7",
|
||||
debug=True,
|
||||
default_encoding="utf-8",
|
||||
)
|
||||
super(Application, self).__init__(handlers, **settings)
|
||||
# Have one global connection to the blog DB across all handlers
|
||||
self.db = torndb.Connection(
|
||||
charset="utf8", max_idle_time=3600, connect_timeout=1000,
|
||||
host=common.MYSQL_HOST, database=common.MYSQL_DB,
|
||||
user=common.MYSQL_USER, password=common.MYSQL_PWD)
|
||||
|
||||
|
||||
# 获得包版本 handler。
|
||||
class PackageVersionHandler(webBase.BaseHandler):
|
||||
@gen.coroutine
|
||||
def get(self):
|
||||
pandasVersion = pd.__version__
|
||||
numpyVersion = np.__version__
|
||||
sqlalchemyVersion = sqlalchemy.__version__
|
||||
akshareVersion = ak.__version__
|
||||
bokehVersion = bh.__version__
|
||||
# 返回包的版本信息。
|
||||
obj = {
|
||||
"code": 20000,
|
||||
"message": "success",
|
||||
"pandasVersion" : pandasVersion,
|
||||
"numpyVersion" : numpyVersion,
|
||||
"sqlalchemyVersion" : sqlalchemyVersion,
|
||||
"akshareVersion" : akshareVersion,
|
||||
"bokehVersion" : bokehVersion,
|
||||
"stockstatsVersion": "0.3.2"
|
||||
}
|
||||
# logging.info("####################")
|
||||
# logging.info(obj)
|
||||
self.write(json.dumps(obj))
|
||||
|
||||
|
||||
# 获得菜单列表数据 handler。
|
||||
class MenuListHandler(webBase.BaseHandler):
|
||||
@gen.coroutine
|
||||
def get(self):
|
||||
|
||||
leftMenuList = stock_web_dic.STOCK_WEB_DATA_LIST
|
||||
out_data = []
|
||||
menu_name = ''
|
||||
menu_children = []
|
||||
index = 0
|
||||
for table_info in leftMenuList:
|
||||
print(table_info.name)
|
||||
index = index + 1
|
||||
# 使用 children 作为二级菜单。
|
||||
tmp_menu = {
|
||||
"name": table_info.name,
|
||||
"path": "/stock/table/" + table_info.table_name
|
||||
}
|
||||
menu_children.append(tmp_menu)
|
||||
|
||||
# 使用 type作为 一级目录
|
||||
if menu_name != table_info.type or index == len(leftMenuList):
|
||||
# 进行数据循环
|
||||
if menu_name != '' :
|
||||
if index != len(leftMenuList):
|
||||
menu_children.pop() # 删除当前的节点信息。
|
||||
tmp_children = list(menu_children)
|
||||
tmp_menu2 = {
|
||||
"name": menu_name,
|
||||
"path": "#",
|
||||
"children": tmp_children
|
||||
}
|
||||
# 下一个数据清空和放置。
|
||||
menu_children = []
|
||||
menu_children.append(tmp_menu)
|
||||
|
||||
out_data.append(tmp_menu2)
|
||||
menu_name = table_info.type
|
||||
|
||||
obj = {
|
||||
"code": 20000,
|
||||
"message": "success",
|
||||
"data": out_data
|
||||
}
|
||||
print(out_data)
|
||||
# self.write(json.dumps(o
|
||||
self.write(json.dumps(obj))
|
||||
|
||||
|
||||
# 首页handler。
|
||||
class HomeHandler(webBase.BaseHandler):
|
||||
@gen.coroutine
|
||||
def get(self):
|
||||
print("################## index.html ##################")
|
||||
pandasVersion = pd.__version__
|
||||
numpyVersion = np.__version__
|
||||
akshareVersion = ak.__version__
|
||||
bokehVersion = bh.__version__
|
||||
#stockstatsVersion = ss.__version__ # 没有这个函数,但是好久不更新了
|
||||
# https://github.com/jealous/stockstats
|
||||
self.render("index.html", pandasVersion=pandasVersion, numpyVersion=numpyVersion,
|
||||
akshareVersion=akshareVersion, bokehVersion=bokehVersion,
|
||||
stockstatsVersion="0.3.2",
|
||||
pythonStockVersion = common.__version__,
|
||||
leftMenu=webBase.GetLeftMenu(self.request.uri))
|
||||
class TestHandler(webBase.BaseHandler):
|
||||
@gen.coroutine
|
||||
def get(self):
|
||||
self.render("test_akshare.html", entries="hello",
|
||||
pythonStockVersion=common.__version__,
|
||||
leftMenu=webBase.GetLeftMenu(self.request.uri))
|
||||
class Test2Handler(webBase.BaseHandler):
|
||||
@gen.coroutine
|
||||
def get(self):
|
||||
self.render("test2.html", entries="hello",
|
||||
pythonStockVersion=common.__version__,
|
||||
leftMenu=webBase.GetLeftMenu(self.request.uri))
|
||||
|
||||
def main():
|
||||
tornado.options.parse_command_line()
|
||||
http_server = tornado.httpserver.HTTPServer(Application())
|
||||
port = 9090
|
||||
http_server.listen(port)
|
||||
# tornado.options.options.logging = "debug"
|
||||
tornado.options.parse_command_line()
|
||||
|
||||
tornado.ioloop.IOLoop.current().start()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Executable
+80
@@ -0,0 +1,80 @@
|
||||
#!/usr/local/bin/python3
|
||||
# -*- coding: utf-8 -*-
|
||||
import os.path
|
||||
import json
|
||||
import subprocess
|
||||
import torndb
|
||||
import tornado.escape
|
||||
from tornado import gen
|
||||
import tornado.httpserver
|
||||
import tornado.ioloop
|
||||
import tornado.options
|
||||
import tornado.web
|
||||
import web.base as webBase
|
||||
import logging
|
||||
import numpy as np
|
||||
from PIL import Image
|
||||
from PIL import ImageOps
|
||||
import base64
|
||||
import io #python2 import StringIO
|
||||
|
||||
work_dir = "/data/stock/tf/minst_serving/input_data"
|
||||
out_dir = "/static/img/minst_serving/%s.bmp"
|
||||
|
||||
|
||||
# 获得页面数据。
|
||||
class GetMinstServingHtmlHandler(webBase.BaseHandler):
|
||||
@gen.coroutine
|
||||
def get(self):
|
||||
# print self.uri_
|
||||
arr = np.arange(30)
|
||||
image_array = []
|
||||
for idx in arr:
|
||||
out_file = out_dir % ("%05d" % idx)
|
||||
print(out_file)
|
||||
image_array.append(out_file)
|
||||
self.render("minst_serving.html", image_array=image_array)
|
||||
|
||||
|
||||
# 获得股票数据内容。
|
||||
class GetPredictionDataHandler(webBase.BaseHandler):
|
||||
def get(self):
|
||||
# 获得分页参数。
|
||||
img_url = self.get_argument("img_url", default=0, strip=False)
|
||||
print(img_url)
|
||||
img_obj = Image.open("/data/stock/web" + img_url)
|
||||
print("img_obj", img_obj)
|
||||
server = "0.0.0.0:8500"
|
||||
prediction = do_inference(server, img_obj)
|
||||
print('######### prediction : ', prediction)
|
||||
self.write(json.dumps(prediction))
|
||||
|
||||
|
||||
# 获得股票数据内容。
|
||||
class GetPrediction2DataHandler(webBase.BaseHandler):
|
||||
def post(self):
|
||||
# 获得分页参数。
|
||||
imgStr = self.get_argument("txt", default="", strip=False)
|
||||
# imgStr.replace(" ", "+")
|
||||
imgStr = base64.b64decode(imgStr)
|
||||
print("imgStr:", type(imgStr))
|
||||
image = Image.open(io.StringIO(imgStr))
|
||||
image.thumbnail((28, 28), Image.ANTIALIAS)
|
||||
image = image.convert('L')
|
||||
image = ImageOps.invert(image)
|
||||
image.save(work_dir + "/web-tmp.bmp", format="BMP") #保存看看,是否
|
||||
#print(image)
|
||||
# img_url = self.get_argument("img_url", default=0, strip=False)
|
||||
# print(img_url)
|
||||
server = "0.0.0.0:8500"
|
||||
prediction = do_inference(server, image)
|
||||
print('######### prediction : ', prediction)
|
||||
self.write(json.dumps(prediction))
|
||||
|
||||
|
||||
|
||||
# 调用 grpc 代码,将图片转换成数组,让后放到 grpc 调用。
|
||||
def do_inference(hostport, img_obj):
|
||||
|
||||
print("############", hostport)
|
||||
|
||||
+1
File diff suppressed because one or more lines are too long
+1
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Vendored
+1
File diff suppressed because one or more lines are too long
+9
@@ -0,0 +1,9 @@
|
||||
/*!
|
||||
* Bootstrap Colorpicker
|
||||
* http://mjolnic.github.io/bootstrap-colorpicker/
|
||||
*
|
||||
* Originally written by (c) 2012 Stefan Petre
|
||||
* Licensed under the Apache License v2.0
|
||||
* http://www.apache.org/licenses/LICENSE-2.0.txt
|
||||
*
|
||||
*/.colorpicker-saturation{float:left;width:100px;height:100px;cursor:crosshair;background-image:url(../images/bootstrap-colorpicker/saturation.png)}.colorpicker-saturation i{position:absolute;top:0;left:0;display:block;width:5px;height:5px;margin:-4px 0 0 -4px;border:1px solid #000;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px}.colorpicker-saturation i b{display:block;width:5px;height:5px;border:1px solid #fff;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px}.colorpicker-alpha,.colorpicker-hue{float:left;width:15px;height:100px;margin-bottom:4px;margin-left:4px;cursor:row-resize}.colorpicker-alpha i,.colorpicker-hue i{position:absolute;top:0;left:0;display:block;width:100%;height:1px;margin-top:-1px;background:#000;border-top:1px solid #fff}.colorpicker-hue{background-image:url(../images/bootstrap-colorpicker/hue.png)}.colorpicker-alpha,.colorpicker-color{background-image:url(../images/bootstrap-colorpicker/alpha.png)}.colorpicker-alpha{display:none}.colorpicker:after,.colorpicker:before{position:absolute;display:inline-block;content:''}.colorpicker-alpha,.colorpicker-hue,.colorpicker-saturation{background-size:contain}.colorpicker{top:0;left:0;z-index:2500;min-width:130px;padding:4px;margin-top:1px;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;*zoom:1}.colorpicker:after,.colorpicker:before{line-height:0}.colorpicker:before{top:-7px;left:6px;border-right:7px solid transparent;border-bottom:7px solid #ccc;border-left:7px solid transparent;border-bottom-color:rgba(0,0,0,.2)}.colorpicker:after{clear:both;top:-6px;left:7px;border-right:6px solid transparent;border-bottom:6px solid #fff;border-left:6px solid transparent}.colorpicker div{position:relative}.colorpicker.colorpicker-with-alpha{min-width:140px}.colorpicker.colorpicker-with-alpha .colorpicker-alpha{display:block}.colorpicker-color{height:10px;margin-top:5px;clear:both;background-position:0 100%}.colorpicker-color div{height:10px}.colorpicker-selectors{display:none;height:10px;margin-top:5px;clear:both}.colorpicker-selectors i{float:left;width:10px;height:10px;cursor:pointer}.colorpicker-selectors i+i{margin-left:3px}.colorpicker-element .add-on i,.colorpicker-element .input-group-addon i{display:inline-block;width:16px;height:16px;vertical-align:text-top;cursor:pointer}.colorpicker.colorpicker-inline{position:relative;z-index:auto;display:inline-block;float:none}.colorpicker.colorpicker-horizontal{width:110px;height:auto;min-width:110px}.colorpicker.colorpicker-horizontal .colorpicker-saturation{margin-bottom:4px}.colorpicker.colorpicker-horizontal .colorpicker-color{width:100px}.colorpicker.colorpicker-horizontal .colorpicker-alpha,.colorpicker.colorpicker-horizontal .colorpicker-hue{float:left;width:100px;height:15px;margin-bottom:4px;margin-left:0;cursor:col-resize}.colorpicker.colorpicker-horizontal .colorpicker-alpha i,.colorpicker.colorpicker-horizontal .colorpicker-hue i{position:absolute;top:0;left:0;display:block;width:1px;height:15px;margin-top:0;background:#fff;border:none}.colorpicker.colorpicker-horizontal .colorpicker-hue{background-image:url(../images/bootstrap-colorpicker/hue-horizontal.png)}.colorpicker.colorpicker-horizontal .colorpicker-alpha{background-image:url(../images/bootstrap-colorpicker/alpha-horizontal.png)}.colorpicker.colorpicker-hidden{display:none}.colorpicker.colorpicker-visible{display:block}.colorpicker-inline.colorpicker-visible{display:inline-block}.colorpicker-right:before{right:6px;left:auto}.colorpicker-right:after{right:7px;left:auto}
|
||||
+7
File diff suppressed because one or more lines are too long
+5
File diff suppressed because one or more lines are too long
+10
@@ -0,0 +1,10 @@
|
||||
/*!
|
||||
* Timepicker Component for Twitter Bootstrap
|
||||
*
|
||||
* Copyright 2013 Joris de Wit
|
||||
*
|
||||
* Contributors https://github.com/jdewit/bootstrap-timepicker/graphs/contributors
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/.bootstrap-timepicker{position:relative}.bootstrap-timepicker.pull-right .bootstrap-timepicker-widget.dropdown-menu{left:auto;right:0}.bootstrap-timepicker.pull-right .bootstrap-timepicker-widget.dropdown-menu:before{left:auto;right:12px}.bootstrap-timepicker.pull-right .bootstrap-timepicker-widget.dropdown-menu:after{left:auto;right:13px}.bootstrap-timepicker .input-group-addon{cursor:pointer}.bootstrap-timepicker .input-group-addon i{display:inline-block;width:16px;height:16px}.bootstrap-timepicker-widget.dropdown-menu{padding:4px}.bootstrap-timepicker-widget.dropdown-menu.open{display:inline-block}.bootstrap-timepicker-widget.dropdown-menu:before{border-bottom:7px solid rgba(0,0,0,.2);border-left:7px solid transparent;border-right:7px solid transparent;content:"";display:inline-block;position:absolute}.bootstrap-timepicker-widget.dropdown-menu:after{border-bottom:6px solid #FFF;border-left:6px solid transparent;border-right:6px solid transparent;content:"";display:inline-block;position:absolute}.bootstrap-timepicker-widget.timepicker-orient-left:before{left:6px}.bootstrap-timepicker-widget.timepicker-orient-left:after{left:7px}.bootstrap-timepicker-widget.timepicker-orient-right:before{right:6px}.bootstrap-timepicker-widget.timepicker-orient-right:after{right:7px}.bootstrap-timepicker-widget.timepicker-orient-top:before{top:-7px}.bootstrap-timepicker-widget.timepicker-orient-top:after{top:-6px}.bootstrap-timepicker-widget.timepicker-orient-bottom:before{bottom:-7px;border-bottom:0;border-top:7px solid #999}.bootstrap-timepicker-widget.timepicker-orient-bottom:after{bottom:-6px;border-bottom:0;border-top:6px solid #fff}.bootstrap-timepicker-widget a.btn,.bootstrap-timepicker-widget input{border-radius:4px}.bootstrap-timepicker-widget table{width:100%;margin:0}.bootstrap-timepicker-widget table td{text-align:center;height:30px;margin:0;padding:2px}.bootstrap-timepicker-widget table td:not(.separator){min-width:30px}.bootstrap-timepicker-widget table td span{width:100%}.bootstrap-timepicker-widget table td a{border:1px solid transparent;width:100%;display:inline-block;margin:0;padding:8px 0;outline:0;color:#333}.bootstrap-timepicker-widget table td a:hover{text-decoration:none;background-color:#eee;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;border-color:#ddd}.bootstrap-timepicker-widget table td a i{margin-top:2px;font-size:18px}.bootstrap-timepicker-widget table td input{width:25px;margin:0;text-align:center}.bootstrap-timepicker-widget .modal-content{padding:4px}@media (min-width:767px){.bootstrap-timepicker-widget.modal{width:200px;margin-left:-100px}}@media (max-width:767px){.bootstrap-timepicker,.bootstrap-timepicker .dropdown-menu{width:100%}}
|
||||
+5
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+11
File diff suppressed because one or more lines are too long
+1
File diff suppressed because one or more lines are too long
+5
File diff suppressed because one or more lines are too long
+4
File diff suppressed because one or more lines are too long
+12
@@ -0,0 +1,12 @@
|
||||
@font-face {
|
||||
font-family: 'Open Sans';
|
||||
font-style: normal;
|
||||
font-weight: 300;
|
||||
src: local('Open Sans Light'), local('OpenSans-Light'), url(/static/font-awesome/opensans/v13/DXI1ORHCpsQm3Vp6mXoaTXhCUOGz7vYGh680lGh-uXM.woff) format('woff');
|
||||
}
|
||||
@font-face {
|
||||
font-family: 'Open Sans';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
src: local('Open Sans'), local('OpenSans'), url(/static/font-awesome/opensans/v13/cJZKeOuBrn4kERxqtaUH3T8E0i7KZn-EPnyo3HZu7kw.woff) format('woff');
|
||||
}
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
/*! jQuery UI - v1.11.4 - 2015-09-20
|
||||
* http://jqueryui.com
|
||||
* Includes: core.css, draggable.css, resizable.css, selectable.css, sortable.css, slider.css
|
||||
* Copyright 2015 jQuery Foundation and other contributors; Licensed MIT */.ui-helper-hidden{display:none}.ui-helper-hidden-accessible{border:0;clip:rect(0 0 0 0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.ui-helper-reset{margin:0;padding:0;border:0;outline:0;line-height:1.3;text-decoration:none;font-size:100%;list-style:none}.ui-helper-clearfix:after,.ui-helper-clearfix:before{content:"";display:table;border-collapse:collapse}.ui-helper-clearfix:after{clear:both}.ui-helper-clearfix{min-height:0}.ui-helper-zfix{width:100%;height:100%;top:0;left:0;position:absolute;opacity:0;filter:Alpha(Opacity=0)}.ui-front{z-index:100}.ui-state-disabled{cursor:default!important}.ui-icon{display:block;text-indent:-99999px;overflow:hidden;background-repeat:no-repeat}.ui-widget-overlay{position:fixed;top:0;left:0;width:100%;height:100%}.ui-draggable-handle{-ms-touch-action:none;touch-action:none}.ui-resizable{position:relative}.ui-resizable-handle{position:absolute;font-size:.1px;display:block;-ms-touch-action:none;touch-action:none}.ui-resizable-autohide .ui-resizable-handle,.ui-resizable-disabled .ui-resizable-handle{display:none}.ui-resizable-n{cursor:n-resize;height:7px;width:100%;top:-5px;left:0}.ui-resizable-s{cursor:s-resize;height:7px;width:100%;bottom:-5px;left:0}.ui-resizable-e{cursor:e-resize;width:7px;right:-5px;top:0;height:100%}.ui-resizable-w{cursor:w-resize;width:7px;left:-5px;top:0;height:100%}.ui-resizable-se{cursor:se-resize;width:12px;height:12px;right:1px;bottom:1px}.ui-resizable-sw{cursor:sw-resize;width:9px;height:9px;left:-5px;bottom:-5px}.ui-resizable-nw{cursor:nw-resize;width:9px;height:9px;left:-5px;top:-5px}.ui-resizable-ne{cursor:ne-resize;width:9px;height:9px;right:-5px;top:-5px}.ui-selectable{-ms-touch-action:none;touch-action:none}.ui-selectable-helper{position:absolute;z-index:100;border:1px dotted #000}.ui-sortable-handle{-ms-touch-action:none;touch-action:none}.ui-slider{position:relative;text-align:left}.ui-slider .ui-slider-handle{position:absolute;z-index:2;width:1.2em;height:1.2em;cursor:default;-ms-touch-action:none;touch-action:none}.ui-slider .ui-slider-range{position:absolute;z-index:1;font-size:.7em;display:block;border:0;background-position:0 0}.ui-slider.ui-state-disabled .ui-slider-handle,.ui-slider.ui-state-disabled .ui-slider-range{filter:inherit}.ui-slider-horizontal{height:.8em}.ui-slider-horizontal .ui-slider-handle{top:-.3em;margin-left:-.6em}.ui-slider-horizontal .ui-slider-range{top:0;height:100%}.ui-slider-horizontal .ui-slider-range-min{left:0}.ui-slider-horizontal .ui-slider-range-max{right:0}.ui-slider-vertical{width:.8em;height:100px}.ui-slider-vertical .ui-slider-handle{left:-.3em;margin-left:0;margin-bottom:-.6em}.ui-slider-vertical .ui-slider-range{left:0;width:100%}.ui-slider-vertical .ui-slider-range-min{bottom:0}.ui-slider-vertical .ui-slider-range-max{top:0}
|
||||
+4
File diff suppressed because one or more lines are too long
@@ -0,0 +1 @@
|
||||
table.dataTable tbody>tr.selected,table.dataTable tbody>tr>.selected{background-color:#B0BED9}table.dataTable.stripe tbody>tr.odd.selected,table.dataTable.stripe tbody>tr.odd>.selected,table.dataTable.display tbody>tr.odd.selected,table.dataTable.display tbody>tr.odd>.selected{background-color:#acbad4}table.dataTable.hover tbody>tr.selected:hover,table.dataTable.hover tbody>tr>.selected:hover,table.dataTable.display tbody>tr.selected:hover,table.dataTable.display tbody>tr>.selected:hover{background-color:#aab7d1}table.dataTable.order-column tbody>tr.selected>.sorting_1,table.dataTable.order-column tbody>tr.selected>.sorting_2,table.dataTable.order-column tbody>tr.selected>.sorting_3,table.dataTable.order-column tbody>tr>.selected,table.dataTable.display tbody>tr.selected>.sorting_1,table.dataTable.display tbody>tr.selected>.sorting_2,table.dataTable.display tbody>tr.selected>.sorting_3,table.dataTable.display tbody>tr>.selected{background-color:#acbad5}table.dataTable.display tbody>tr.odd.selected>.sorting_1,table.dataTable.order-column.stripe tbody>tr.odd.selected>.sorting_1{background-color:#a6b4cd}table.dataTable.display tbody>tr.odd.selected>.sorting_2,table.dataTable.order-column.stripe tbody>tr.odd.selected>.sorting_2{background-color:#a8b5cf}table.dataTable.display tbody>tr.odd.selected>.sorting_3,table.dataTable.order-column.stripe tbody>tr.odd.selected>.sorting_3{background-color:#a9b7d1}table.dataTable.display tbody>tr.even.selected>.sorting_1,table.dataTable.order-column.stripe tbody>tr.even.selected>.sorting_1{background-color:#acbad5}table.dataTable.display tbody>tr.even.selected>.sorting_2,table.dataTable.order-column.stripe tbody>tr.even.selected>.sorting_2{background-color:#aebcd6}table.dataTable.display tbody>tr.even.selected>.sorting_3,table.dataTable.order-column.stripe tbody>tr.even.selected>.sorting_3{background-color:#afbdd8}table.dataTable.display tbody>tr.odd>.selected,table.dataTable.order-column.stripe tbody>tr.odd>.selected{background-color:#a6b4cd}table.dataTable.display tbody>tr.even>.selected,table.dataTable.order-column.stripe tbody>tr.even>.selected{background-color:#acbad5}table.dataTable.display tbody>tr.selected:hover>.sorting_1,table.dataTable.order-column.hover tbody>tr.selected:hover>.sorting_1{background-color:#a2aec7}table.dataTable.display tbody>tr.selected:hover>.sorting_2,table.dataTable.order-column.hover tbody>tr.selected:hover>.sorting_2{background-color:#a3b0c9}table.dataTable.display tbody>tr.selected:hover>.sorting_3,table.dataTable.order-column.hover tbody>tr.selected:hover>.sorting_3{background-color:#a5b2cb}table.dataTable.display tbody>tr:hover>.selected,table.dataTable.display tbody>tr>.selected:hover,table.dataTable.order-column.hover tbody>tr:hover>.selected,table.dataTable.order-column.hover tbody>tr>.selected:hover{background-color:#a2aec7}table.dataTable tbody td.select-checkbox,table.dataTable tbody th.select-checkbox{position:relative}table.dataTable tbody td.select-checkbox:before,table.dataTable tbody td.select-checkbox:after,table.dataTable tbody th.select-checkbox:before,table.dataTable tbody th.select-checkbox:after{display:block;position:absolute;top:1.2em;left:50%;width:12px;height:12px;box-sizing:border-box}table.dataTable tbody td.select-checkbox:before,table.dataTable tbody th.select-checkbox:before{content:' ';margin-top:-6px;margin-left:-6px;border:1px solid black;border-radius:3px}table.dataTable tr.selected td.select-checkbox:after,table.dataTable tr.selected th.select-checkbox:after{content:'\2714';margin-top:-11px;margin-left:-4px;text-align:center;text-shadow:1px 1px #B0BED9, -1px -1px #B0BED9, 1px -1px #B0BED9, -1px 1px #B0BED9}div.dataTables_wrapper span.select-info,div.dataTables_wrapper span.select-item{margin-left:0.5em}@media screen and (max-width: 640px){div.dataTables_wrapper span.select-info,div.dataTables_wrapper span.select-item{margin-left:0;display:block}}
|
||||
+4
File diff suppressed because one or more lines are too long
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
Binary file not shown.
|
After Width: | Height: | Size: 124 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 344 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 138 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 138 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 111 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 204 KiB |
+5
File diff suppressed because one or more lines are too long
+1
File diff suppressed because one or more lines are too long
+5
File diff suppressed because one or more lines are too long
+6
@@ -0,0 +1,6 @@
|
||||
/*!
|
||||
Autosize 3.0.15
|
||||
license: MIT
|
||||
http://www.jacklmoore.com/autosize
|
||||
*/
|
||||
!function(a,b){if("function"==typeof define&&define.amd)define(["exports","module"],b);else if("undefined"!=typeof exports&&"undefined"!=typeof module)b(exports,module);else{var c={exports:{}};b(c.exports,c),a.autosize=c.exports}}(this,function(a,b){"use strict";function c(a){function b(){var b=window.getComputedStyle(a,null);n=b.overflowY,"vertical"===b.resize?a.style.resize="none":"both"===b.resize&&(a.style.resize="horizontal"),m="content-box"===b.boxSizing?-(parseFloat(b.paddingTop)+parseFloat(b.paddingBottom)):parseFloat(b.borderTopWidth)+parseFloat(b.borderBottomWidth),isNaN(m)&&(m=0),e()}function c(b){var c=a.style.width;a.style.width="0px",a.offsetWidth,a.style.width=c,n=b,l&&(a.style.overflowY=b),d()}function d(){var b=window.pageYOffset,c=document.body.scrollTop,d=a.style.height;a.style.height="auto";var e=a.scrollHeight+m;return 0===a.scrollHeight?void(a.style.height=d):(a.style.height=e+"px",o=a.clientWidth,document.documentElement.scrollTop=b,void(document.body.scrollTop=c))}function e(){var b=a.style.height;d();var e=window.getComputedStyle(a,null);if(e.height!==a.style.height?"visible"!==n&&c("visible"):"hidden"!==n&&c("hidden"),b!==a.style.height){var f=g("autosize:resized");a.dispatchEvent(f)}}var h=void 0===arguments[1]?{}:arguments[1],i=h.setOverflowX,j=void 0===i?!0:i,k=h.setOverflowY,l=void 0===k?!0:k;if(a&&a.nodeName&&"TEXTAREA"===a.nodeName&&!f.has(a)){var m=null,n=null,o=a.clientWidth,p=function(){a.clientWidth!==o&&e()},q=function(b){window.removeEventListener("resize",p,!1),a.removeEventListener("input",e,!1),a.removeEventListener("keyup",e,!1),a.removeEventListener("autosize:destroy",q,!1),a.removeEventListener("autosize:update",e,!1),f["delete"](a),Object.keys(b).forEach(function(c){a.style[c]=b[c]})}.bind(a,{height:a.style.height,resize:a.style.resize,overflowY:a.style.overflowY,overflowX:a.style.overflowX,wordWrap:a.style.wordWrap});a.addEventListener("autosize:destroy",q,!1),"onpropertychange"in a&&"oninput"in a&&a.addEventListener("keyup",e,!1),window.addEventListener("resize",p,!1),a.addEventListener("input",e,!1),a.addEventListener("autosize:update",e,!1),f.add(a),j&&(a.style.overflowX="hidden",a.style.wordWrap="break-word"),b()}}function d(a){if(a&&a.nodeName&&"TEXTAREA"===a.nodeName){var b=g("autosize:destroy");a.dispatchEvent(b)}}function e(a){if(a&&a.nodeName&&"TEXTAREA"===a.nodeName){var b=g("autosize:update");a.dispatchEvent(b)}}var f="function"==typeof Set?new Set:function(){var a=[];return{has:function(b){return Boolean(a.indexOf(b)>-1)},add:function(b){a.push(b)},"delete":function(b){a.splice(a.indexOf(b),1)}}}(),g=function(a){return new Event(a)};try{new Event("test")}catch(h){g=function(a){var b=document.createEvent("Event");return b.initEvent(a,!0,!1),b}}var i=null;"undefined"==typeof window||"function"!=typeof window.getComputedStyle?(i=function(a){return a},i.destroy=function(a){return a},i.update=function(a){return a}):(i=function(a,b){return a&&Array.prototype.forEach.call(a.length?a:[a],function(a){return c(a,b)}),a},i.destroy=function(a){return a&&Array.prototype.forEach.call(a.length?a:[a],d),a},i.update=function(a){return a&&Array.prototype.forEach.call(a.length?a:[a],e),a}),b.exports=i});
|
||||
+53
File diff suppressed because one or more lines are too long
+74
File diff suppressed because one or more lines are too long
+132
File diff suppressed because one or more lines are too long
+118
File diff suppressed because one or more lines are too long
Vendored
+596
File diff suppressed because one or more lines are too long
+6
File diff suppressed because one or more lines are too long
+9
File diff suppressed because one or more lines are too long
+18
@@ -0,0 +1,18 @@
|
||||
/**
|
||||
* Simplified Chinese translation for bootstrap-datepicker
|
||||
* Yuan Cheung <advanimal@gmail.com>
|
||||
*/
|
||||
;(function($){
|
||||
$.fn.datepicker.dates['zh-CN'] = {
|
||||
days: ["星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六"],
|
||||
daysShort: ["周日", "周一", "周二", "周三", "周四", "周五", "周六"],
|
||||
daysMin: ["日", "一", "二", "三", "四", "五", "六"],
|
||||
months: ["一月", "二月", "三月", "四月", "五月", "六月", "七月", "八月", "九月", "十月", "十一月", "十二月"],
|
||||
monthsShort: ["1月", "2月", "3月", "4月", "5月", "6月", "7月", "8月", "9月", "10月", "11月", "12月"],
|
||||
today: "今日",
|
||||
clear: "清除",
|
||||
format: "yyyy年mm月dd日",
|
||||
titleFormat: "yyyy年mm月",
|
||||
weekStart: 1
|
||||
};
|
||||
}(jQuery));
|
||||
+9
File diff suppressed because one or more lines are too long
+11
File diff suppressed because one or more lines are too long
+7
File diff suppressed because one or more lines are too long
+5
@@ -0,0 +1,5 @@
|
||||
/*!
|
||||
* Column visibility buttons for Buttons and DataTables.
|
||||
* 2015 SpryMedia Ltd - datatables.net/license
|
||||
*/
|
||||
!function(a){"function"==typeof define&&define.amd?define(["jquery","datatables.net","datatables.net-buttons"],function(b){return a(b,window,document)}):"object"==typeof exports?module.exports=function(b,c){return b||(b=window),c&&c.fn.dataTable||(c=require("datatables.net")(b,c).$),c.fn.dataTable.Buttons||require("datatables.net-buttons")(b,c),a(c,b,b.document)}:a(jQuery,window,document)}(function(a,b,c,d){"use strict";var e=a.fn.dataTable;return a.extend(e.ext.buttons,{colvis:function(a,b){return{extend:"collection",text:function(a){return a.i18n("buttons.colvis","Column visibility")},className:"buttons-colvis",buttons:[{extend:"columnsToggle",columns:b.columns}]}},columnsToggle:function(a,b){var c=a.columns(b.columns).indexes().map(function(a){return{extend:"columnToggle",columns:a}}).toArray();return c},columnToggle:function(a,b){return{extend:"columnVisibility",columns:b.columns}},columnsVisibility:function(a,b){var c=a.columns(b.columns).indexes().map(function(a){return{extend:"columnVisibility",columns:a,visibility:b.visibility}}).toArray();return c},columnVisibility:{columns:d,text:function(a,b,c){return c._columnText(a,c.columns)},className:"buttons-columnVisibility",action:function(a,b,c,e){var f=b.columns(e.columns),g=f.visible();f.visible(e.visibility!==d?e.visibility:!(g.length?g[0]:!1))},init:function(a,b,c){var d=this,e=a.column(c.columns);a.on("column-visibility.dt"+c.namespace,function(a,b,e,f){b.bDestroying||e!==c.columns||d.active(f)}).on("column-reorder.dt"+c.namespace,function(b,e,f){if(1===a.columns(c.columns).count()){"number"==typeof c.columns&&(c.columns=f.mapping[c.columns]);var g=a.column(c.columns);d.text(c._columnText(a,c.columns)),d.active(g.visible())}}),this.active(e.visible())},destroy:function(a,b,c){a.off("column-visibility.dt"+c.namespace).off("column-reorder.dt"+c.namespace)},_columnText:function(a,b){var c=a.column(b).index();return a.settings()[0].aoColumns[c].sTitle.replace(/\n/g," ").replace(/<.*?>/g,"").replace(/^\s+|\s+$/g,"")}},colvisRestore:{className:"buttons-colvisRestore",text:function(a){return a.i18n("buttons.colvisRestore","Restore visibility")},init:function(a,b,c){c._visOriginal=a.columns().indexes().map(function(b){return a.column(b).visible()}).toArray()},action:function(a,b,c,d){b.columns().every(function(a){var c=b.colReorder&&b.colReorder.transpose?b.colReorder.transpose(a,"toOriginal"):a;this.visible(d._visOriginal[c])})}},colvisGroup:{className:"buttons-colvisGroup",action:function(a,b,c,d){b.columns(d.show).visible(!0),b.columns(d.hide).visible(!1)},show:[],hide:[]}}),e.Buttons});
|
||||
+8
File diff suppressed because one or more lines are too long
+5
@@ -0,0 +1,5 @@
|
||||
/*!
|
||||
* Print button for Buttons and DataTables.
|
||||
* 2015 SpryMedia Ltd - datatables.net/license
|
||||
*/
|
||||
!function(a){"function"==typeof define&&define.amd?define(["jquery","datatables.net","datatables.net-buttons"],function(b){return a(b,window,document)}):"object"==typeof exports?module.exports=function(b,c){return b||(b=window),c&&c.fn.dataTable||(c=require("datatables.net")(b,c).$),c.fn.dataTable.Buttons||require("datatables.net-buttons")(b,c),a(c,b,b.document)}:a(jQuery,window,document)}(function(a,b,c,d){"use strict";var e=a.fn.dataTable,f=c.createElement("a"),g=function(b){var c,d=a(b).clone()[0];return"link"===d.nodeName.toLowerCase()&&(f.href=d.href,c=f.host,-1===c.indexOf("/")&&0!==f.pathname.indexOf("/")&&(c+="/"),d.href=f.protocol+"//"+c+f.pathname+f.search),d.outerHTML};return e.ext.buttons.print={className:"buttons-print",text:function(a){return a.i18n("buttons.print","Print")},action:function(c,d,e,f){var h=d.buttons.exportData(f.exportOptions),i=function(a,b){for(var c="<tr>",d=0,e=a.length;e>d;d++)c+="<"+b+">"+a[d]+"</"+b+">";return c+"</tr>"},j='<table class="'+d.table().node().className+'">';f.header&&(j+="<thead>"+i(h.header,"th")+"</thead>"),j+="<tbody>";for(var k=0,l=h.body.length;l>k;k++)j+=i(h.body[k],"td");j+="</tbody>",f.footer&&(j+="<tfoot>"+i(h.footer,"th")+"</tfoot>");var m=b.open("",""),n=f.title;"function"==typeof n&&(n=n()),-1!==n.indexOf("*")&&(n=n.replace("*",a("title").text())),m.document.close();var o="<title>"+n+"</title>";a("style, link").each(function(){o+=g(this)}),a(m.document.head).html(o),a(m.document.body).html("<h1>"+n+"</h1><div>"+f.message+"</div>"+j),f.customize&&f.customize(m),setTimeout(function(){f.autoPrint&&(m.print(),m.close())},250)},title:"*",message:"",exportOptions:{},header:!0,footer:!1,autoPrint:!0,customize:null},e.Buttons});
|
||||
+1
File diff suppressed because one or more lines are too long
+4
File diff suppressed because one or more lines are too long
+1327
File diff suppressed because one or more lines are too long
+4
File diff suppressed because one or more lines are too long
@@ -0,0 +1,24 @@
|
||||
{
|
||||
"sProcessing": "处理中...",
|
||||
"sLengthMenu": "显示 _MENU_ 项结果",
|
||||
"sZeroRecords": "没有匹配结果",
|
||||
"sInfo": "显示第 _START_ 至 _END_ 项结果,共 _TOTAL_ 项",
|
||||
"sInfoEmpty": "显示第 0 至 0 项结果,共 0 项",
|
||||
"sInfoFiltered": "(由 _MAX_ 项结果过滤)",
|
||||
"sInfoPostFix": "",
|
||||
"sSearch": "搜索:",
|
||||
"sUrl": "",
|
||||
"sEmptyTable": "表中数据为空",
|
||||
"sLoadingRecords": "载入中...",
|
||||
"sInfoThousands": ",",
|
||||
"oPaginate": {
|
||||
"sFirst": "首页",
|
||||
"sPrevious": "上页",
|
||||
"sNext": "下页",
|
||||
"sLast": "末页"
|
||||
},
|
||||
"oAria": {
|
||||
"sSortAscending": ": 以升序排列此列",
|
||||
"sSortDescending": ": 以降序排列此列"
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user