From 0c4dd6ad721fba8470597bb9ee037b5cdfa58c2a Mon Sep 17 00:00:00 2001 From: zengbin93 Date: Fri, 19 Jul 2019 00:00:03 +0800 Subject: [PATCH] modify - 20190718 --- README.md | 6 ++- chan/__init__.py | 5 +- chan/a/__init__.py | 2 +- chan/a/calendar.py | 104 ++++++++++++++++++++++++++++++++++++++ chan/a/daily_classfier.py | 5 ++ chan/a/utils.py | 35 +++++++++++-- chan/analyze.py | 6 --- requirements.txt | 2 + 8 files changed, 151 insertions(+), 14 deletions(-) create mode 100644 chan/a/calendar.py diff --git a/README.md b/README.md index 5fda728..e4c9464 100644 --- a/README.md +++ b/README.md @@ -22,4 +22,8 @@ pip install git+git://github.com/zengbin93/chan.git ``` * vr 表示 量比 -* dt 表示 该周期的交易结束时间 \ No newline at end of file +* dt 表示 该周期的交易结束时间 + + +### K线绘图 + diff --git a/chan/__init__.py b/chan/__init__.py index a85c54c..5a82c9b 100644 --- a/chan/__init__.py +++ b/chan/__init__.py @@ -1,5 +1,5 @@ # coding: utf-8 - +import os from . import a @@ -8,3 +8,6 @@ version = "0.0.1" email = "zeng_bin8888@163.com" +cache_path = os.path.join(os.path.expanduser('~'), ".chan") + + diff --git a/chan/a/__init__.py b/chan/a/__init__.py index 0499e3a..c42d845 100644 --- a/chan/a/__init__.py +++ b/chan/a/__init__.py @@ -6,4 +6,4 @@ """ from .daily_classfier import daily_classifier -from .utils import get_kline +from .utils import get_kline, get_realtime_kline diff --git a/chan/a/calendar.py b/chan/a/calendar.py new file mode 100644 index 0000000..f377722 --- /dev/null +++ b/chan/a/calendar.py @@ -0,0 +1,104 @@ +# coding: utf-8 + +import os +import time +import functools +import tushare as ts +import pandas as pd +import warnings +from datetime import datetime + +from chan import cache_path + +# A股交易日历 +# -------------------------------------------------------------------- +FILE_CALENDAR = os.path.join(cache_path, 'calendar.csv') +if os.path.exists(FILE_CALENDAR) and \ + time.time() - os.path.getmtime(FILE_CALENDAR) < 3600 * 24 * 300: + trade_calendar = pd.read_csv(FILE_CALENDAR, encoding='utf-8') +else: + trade_calendar = ts.trade_cal() # tushare提供的交易日历 + trade_calendar.to_csv(FILE_CALENDAR, index=False, encoding='utf-8') + + +def is_trade_day(date): + """判断date日期是不是交易日 + + :param date: str or datetime.date, 如 2018-03-15 + :return: Bool + """ + trade_day = trade_calendar[trade_calendar["isOpen"] == 1] + trade_day_list = list(trade_day['calendarDate']) + if isinstance(date, datetime): + date = str(date.date()) + if date in trade_day_list: + return True + else: + return False + + +def in_trade_time(): + """判断当前是否是交易时间""" + today = str(datetime.now().date()) + if not is_trade_day(today): # 如果今天不是交易日,返回False + return False + t1 = today + " " + "09:30:00" + t1 = datetime.strptime(t1, "%Y-%m-%d %H:%M:%S") + t2 = today + " " + "11:30:00" + t2 = datetime.strptime(t2, "%Y-%m-%d %H:%M:%S") + t3 = today + " " + "13:00:00" + t3 = datetime.strptime(t3, "%Y-%m-%d %H:%M:%S") + t4 = today + " " + "15:00:00" + t4 = datetime.strptime(t4, "%Y-%m-%d %H:%M:%S") + if t1 <= datetime.now() <= t2 or t3 <= datetime.now() <= t4: + return True + else: + return False + + +def recent_trade_days(date, n=10): + """返回任一日期date前后的n个交易日日期 + + :param n: int + 返回交易日的数量n。 + 如果 n > 0,则返回date日期未来的n个交易日日期; + 如果 n < 0,则返回date日期过去的n个交易日日期。 + :param date: str 默认值 today + :return: list + n个交易日日期列表 + """ + cal_date = list(trade_calendar['calendarDate']) + date_index = cal_date.index(date) + if n >= 0: + recent_days = cal_date[date_index:date_index + n + 20] + else: + recent_days = cal_date[date_index + n - 20:date_index + 1] + recent_days = recent_days[::-1] + + res = [] + for d in recent_days: + if is_trade_day(d): + res.append(d) + if len(res) == abs(n): + break + return res + + +def run_at_trade_time(func): + """控制函数func仅在交易时间段运行""" + + @functools.wraps(func) + def wrapper(*args, **kw): + if in_trade_time(): + res = func(*args, **kw) + else: + msg = "%s 不是交易时间,函数 %s 仅在交易时间执行" % ( + datetime.now().__str__(), func.__name__ + ) + warnings.warn(msg) + res = None + return res + + return wrapper + + diff --git a/chan/a/daily_classfier.py b/chan/a/daily_classfier.py index b444f2d..3eee70a 100644 --- a/chan/a/daily_classfier.py +++ b/chan/a/daily_classfier.py @@ -21,6 +21,7 @@ def daily_classifier(ts_code, trade_date, return_central=False): >>> kind, central = daily_classifier('600122.SH', "20190613", return_central=True) >>> print(kind, central) """ + start_date = datetime.strptime(trade_date, '%Y%m%d') end_date = start_date + timedelta(days=1) end_date = end_date.date().__str__().replace("-", "") @@ -62,12 +63,15 @@ def daily_classifier(ts_code, trade_date, return_central=False): elif (first_central is None and last_central) or (first_central and last_central is None): max_p = max(data.iloc[:3, :]['close']) min_p = min(data.iloc[:3, :]['close']) + # 1、在前三根30分钟K线出现当天高点 if max(data['close']) == max_p: kind = "弱平衡市" + # 2、在前三根30分钟K线出现当天低点 elif min(data['close']) == min_p: kind = "强平衡市" + # 3、在前三根30分钟K线不出现当天高低点 else: kind = "转折平衡市" @@ -80,6 +84,7 @@ def daily_classifier(ts_code, trade_date, return_central=False): kind = "向上两中枢走势" else: raise ValueError("两中枢的最低价不可以相等") + else: raise ValueError('中枢计算错误') diff --git a/chan/a/utils.py b/chan/a/utils.py index d703f1c..2636050 100644 --- a/chan/a/utils.py +++ b/chan/a/utils.py @@ -15,7 +15,7 @@ def get_kline(ts_code, start_date, end_date, freq='30min'): :param end_date: str 日期,如 20190610 :return: pd.DataFrame - columns = ["symbol", "dt", "open", "close", "high", "low", "vr"] + columns = ["symbol", "dt", "open", "close", "high", "low", "vol"] example: >>> get_kline(ts_code='600122.SH', start_date='20190601', end_date='20190610', freq='30min') @@ -33,10 +33,35 @@ def get_kline(ts_code, start_date, end_date, freq='30min'): df.sort_values('dt', inplace=True) df.reset_index(drop=True, inplace=True) - df['vr'] = 0 - for i in range(5, len(df)): - df.loc[i, 'vr'] = round(df.loc[i, 'vol'] / df.loc[i-5:i-1, 'vol'].mean(), 4) - return df[['symbol', 'dt', 'open', 'close', 'high', 'low', 'vr']] + # 计算量比 + # df['vr'] = 0 + # for i in range(5, len(df)): + # df.loc[i, 'vr'] = round(df.loc[i, 'vol'] / df.loc[i-5:i-1, 'vol'].mean(), 4) + + return df[['symbol', 'dt', 'open', 'close', 'high', 'low', 'vol']] + + +def get_realtime_kline(ts_code, freq="5min"): + """实时获取分钟K线 + + :param ts_code: str + tushare 股票代码,如 600122.SH + :param freq: str + K线周期,分钟级别,可选值 5min 15min 30min 60min + + :return: pd.DataFrame + columns = ["symbol", "dt", "open", "close", "high", "low", "vol"] + + """ + code = ts_code[:6] + + df = ts.get_k_data(code=code, ktype=freq.replace("min", "")) + df['symbol'] = ts_code + df.rename(columns={'date': 'dt', 'volume': 'vol'}, inplace=True) + df.sort_values('dt', inplace=True) + df.reset_index(drop=True, inplace=True) + + return df[["symbol", "dt", "open", "close", "high", "low", "vol"]] diff --git a/chan/analyze.py b/chan/analyze.py index e6add27..9575019 100644 --- a/chan/analyze.py +++ b/chan/analyze.py @@ -80,9 +80,3 @@ def find_fx(kline): return kline -def find_bi(kline): - kline1 = kline.dropna(axis=0, how='any', subset=['fx']) - kline2 = kline.dropna(axis=0, how='any', subset=['high_m', 'low_m']) - pass - - diff --git a/requirements.txt b/requirements.txt index ff5064f..fd9a876 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1 +1,3 @@ +tqdm +pandas tushare -- GitLab