Initial commit

This commit is contained in:
jackyu66git
2025-06-10 01:16:09 +08:00
commit 05bab03b8c
155 changed files with 19979 additions and 0 deletions
+137
View File
@@ -0,0 +1,137 @@
from enum import Enum, auto
from typing import Literal
class DATA_SRC(Enum):
BAO_STOCK = auto()
CCXT = auto()
CSV = auto()
class KL_TYPE(Enum):
K_1M = auto()
K_DAY = auto()
K_WEEK = auto()
K_MON = auto()
K_YEAR = auto()
K_5M = auto()
K_15M = auto()
K_30M = auto()
K_60M = auto()
K_4H = auto()
K_6H = auto()
K_8H = auto()
K_12H = auto()
K_3DAY = auto()
K_3M = auto()
K_QUARTER = auto()
class KLINE_DIR(Enum):
UP = auto()
DOWN = auto()
COMBINE = auto()
INCLUDED = auto()
class FX_TYPE(Enum):
BOTTOM = auto()
TOP = auto()
UNKNOWN = auto()
class BI_DIR(Enum):
UP = auto()
DOWN = auto()
class SEG_DIR(Enum):
UP = auto()
DOWN = auto()
class BI_TYPE(Enum):
UNKNOWN = auto()
STRICT = auto()
SUB_VALUE = auto() # 次高低点成笔
TIAOKONG_THRED = auto()
DAHENG = auto()
TUIBI = auto()
UNSTRICT = auto()
TIAOKONG_VALUE = auto()
BSP_MAIN_TYPE = Literal['1', '2', '3']
class BSP_TYPE(Enum):
T1 = '1'
T1P = '1p'
T2 = '2'
T2S = '2s'
T3A = '3a' # 中枢在1类后面
T3B = '3b' # 中枢在1类前面
def main_type(self) -> BSP_MAIN_TYPE:
return self.value[0] # type: ignore
class AUTYPE(Enum):
QFQ = auto()
HFQ = auto()
NONE = auto()
class TREND_TYPE(Enum):
MEAN = "mean"
MAX = "max"
MIN = "min"
class TREND_LINE_SIDE(Enum):
INSIDE = auto()
OUTSIDE = auto()
class LEFT_SEG_METHOD(Enum):
ALL = auto()
PEAK = auto()
class FX_CHECK_METHOD(Enum):
STRICT = auto()
LOSS = auto()
HALF = auto()
TOTALLY = auto()
class SEG_TYPE(Enum):
BI = auto()
SEG = auto()
class MACD_ALGO(Enum):
AREA = auto()
PEAK = auto()
FULL_AREA = auto()
DIFF = auto()
SLOPE = auto()
AMP = auto()
VOLUMN = auto()
AMOUNT = auto()
VOLUMN_AVG = auto()
AMOUNT_AVG = auto()
TURNRATE_AVG = auto()
RSI = auto()
class DATA_FIELD:
FIELD_TIME = "time_key"
FIELD_OPEN = "open"
FIELD_HIGH = "high"
FIELD_LOW = "low"
FIELD_CLOSE = "close"
FIELD_VOLUME = "volume" # 成交量
FIELD_TURNOVER = "turnover" # 成交额
FIELD_TURNRATE = "turnover_rate" # 换手率
TRADE_INFO_LST = [DATA_FIELD.FIELD_VOLUME, DATA_FIELD.FIELD_TURNOVER, DATA_FIELD.FIELD_TURNRATE]
+44
View File
@@ -0,0 +1,44 @@
from datetime import datetime
class CTime:
def __init__(self, year, month, day, hour, minute, second=0, auto=True):
self.year = year
self.month = month
self.day = day
self.hour = hour
self.minute = minute
self.second = second
self.auto = auto # 自适应对天的理解
self.set_timestamp() # set self.ts
def __str__(self):
if self.hour == 0 and self.minute == 0:
return f"{self.year:04}/{self.month:02}/{self.day:02}"
else:
return f"{self.year:04}/{self.month:02}/{self.day:02} {self.hour:02}:{self.minute:02}"
def to_str(self):
if self.hour == 0 and self.minute == 0:
return f"{self.year:04}/{self.month:02}/{self.day:02}"
else:
return f"{self.year:04}/{self.month:02}/{self.day:02} {self.hour:02}:{self.minute:02}"
def toDateStr(self, splt=''):
return f"{self.year:04}{splt}{self.month:02}{splt}{self.day:02}"
def toDate(self):
return CTime(self.year, self.month, self.day, 0, 0, auto=False)
def set_timestamp(self):
if self.hour == 0 and self.minute == 0 and self.auto:
date = datetime(self.year, self.month, self.day, 23, 59, self.second)
else:
date = datetime(self.year, self.month, self.day, self.hour, self.minute, self.second)
self.ts = date.timestamp()
def __gt__(self, t2):
return self.ts > t2.ts
def __ge__(self, t2):
return self.ts >= t2.ts
+88
View File
@@ -0,0 +1,88 @@
from enum import IntEnum
class ErrCode(IntEnum):
# chan err
_CHAN_ERR_BEGIN = 0
COMMON_ERROR = 1
SRC_DATA_NOT_FOUND = 3
SRC_DATA_TYPE_ERR = 4
PARA_ERROR = 5
EXTRA_KLU_ERR = 6
SEG_END_VALUE_ERR = 7
SEG_EIGEN_ERR = 8
BI_ERR = 9
COMBINER_ERR = 10
PLOT_ERR = 11
MODEL_ERROR = 12
SEG_LEN_ERR = 13
ENV_CONF_ERR = 14
UNKNOWN_DB_TYPE = 15
FEATURE_ERROR = 16
CONFIG_ERROR = 17
SRC_DATA_FORMAT_ERROR = 18
_CHAN_ERR_END = 99
# Trade Error
_TRADE_ERR_BEGIN = 100
SIGNAL_EXISTED = 101
RECORD_NOT_EXIST = 102
RECORD_ALREADY_OPENED = 103
QUOTA_NOT_ENOUGH = 104
RECORD_NOT_OPENED = 105
TRADE_UNLOCK_FAIL = 106
PLACE_ORDER_FAIL = 107
LIST_ORDER_FAIL = 108
CANDEL_ORDER_FAIL = 109
GET_FUTU_PRICE_FAIL = 110
GET_FUTU_LOT_SIZE_FAIL = 111
OPEN_RECORD_NOT_WATCHING = 112
GET_HOLDING_QTY_FAIL = 113
RECORD_CLOSED = 114
REQUEST_TRADING_DAYS_FAIL = 115
COVER_ORDER_ID_NOT_UNIQUE = 116
SIGNAL_TRADED = 117
_TRADE_ERR_END = 199
# KL data Error
_KL_ERR_BEGIN = 200
PRICE_BELOW_ZERO = 201
KL_DATA_NOT_ALIGN = 202
KL_DATA_INVALID = 203
KL_TIME_INCONSISTENT = 204
TRADEINFO_TOO_MUCH_ZERO = 205
KL_NOT_MONOTONOUS = 206
SNAPSHOT_ERR = 207
SUSPENSION = 208 # 疑似停牌
STOCK_IPO_TOO_LATE = 209
NO_DATA = 210
STOCK_NOT_ACTIVE = 211
STOCK_PRICE_NOT_ACTIVE = 212
_KL_ERR_END = 299
class CChanException(Exception):
def __init__(self, message, code=ErrCode.COMMON_ERROR):
self.errcode = code
self.msg = message
Exception.__init__(self, message)
def is_kldata_err(self):
return ErrCode._KL_ERR_BEGIN < self.errcode < ErrCode._KL_ERR_END
def is_chan_err(self):
return ErrCode._CHAN_ERR_BEGIN < self.errcode < ErrCode._CHAN_ERR_END
if __name__ == "__main__":
def foo():
raise CChanException("XXX", ErrCode.CONFIG_ERROR)
try:
foo()
except CChanException as e:
print(str(e.errcode))
# python3.8 结果为: ErrCode.CONFIG_ERROR
# python3.11 结果为:17
print(e.errcode.name, type(e.errcode.name))
View File
+34
View File
@@ -0,0 +1,34 @@
import inspect
import types
class make_cache:
def __init__(self, func):
self.func = func
fargspec = inspect.getfullargspec(func)
if len(fargspec.args) != 1 or fargspec.args[0] != "self":
raise Exception("@memoize must be `(self)`")
# set key for this function
self.func_key = str(func)
def __get__(self, instance, cls):
if instance is None:
raise Exception("@memoize's must be bound")
if not hasattr(instance, "_memoize_cache"):
setattr(instance, "_memoize_cache", {})
return types.MethodType(self, instance)
def __call__(self, *args, **kwargs):
instance = args[0]
cache = instance._memoize_cache
if self.func_key in cache:
return cache[self.func_key]
result = self.func(*args, **kwargs)
cache[self.func_key] = result
return result
+59
View File
@@ -0,0 +1,59 @@
from .CEnum import BI_DIR, KL_TYPE
def kltype_lt_day(_type):
return _type in [KL_TYPE.K_1M, KL_TYPE.K_5M, KL_TYPE.K_15M, KL_TYPE.K_30M, KL_TYPE.K_60M]
def kltype_lte_day(_type):
return _type in [KL_TYPE.K_1M, KL_TYPE.K_5M, KL_TYPE.K_15M, KL_TYPE.K_30M, KL_TYPE.K_60M, KL_TYPE.K_DAY]
def check_kltype_order(type_list: list):
_dict = {
KL_TYPE.K_1M: 1,
KL_TYPE.K_3M: 2,
KL_TYPE.K_5M: 3,
KL_TYPE.K_15M: 4,
KL_TYPE.K_30M: 5,
KL_TYPE.K_60M: 6,
KL_TYPE.K_4H: 7, # 4小时
KL_TYPE.K_6H: 8, # 6小时
KL_TYPE.K_8H: 9, # 8小时
KL_TYPE.K_12H: 10, # 12小时
KL_TYPE.K_DAY: 11,
KL_TYPE.K_3DAY: 12, # 3日线
KL_TYPE.K_WEEK: 13,
KL_TYPE.K_MON: 14,
KL_TYPE.K_QUARTER: 15,
KL_TYPE.K_YEAR: 16,
}
last_lv = float("inf")
for kl_type in type_list:
cur_lv = _dict[kl_type]
assert cur_lv < last_lv, "lv_list的顺序必须从大级别到小级别"
last_lv = cur_lv
def revert_bi_dir(dir):
return BI_DIR.DOWN if dir == BI_DIR.UP else BI_DIR.UP
def has_overlap(l1, h1, l2, h2, equal=False):
return h2 >= l1 and h1 >= l2 if equal else h2 > l1 and h1 > l2
def str2float(s):
try:
return float(s)
except ValueError:
return 0.0
def _parse_inf(v):
if type(v) == float:
if v == float("inf"):
v = 'float("inf")'
if v == float("-inf"):
v = 'float("-inf")'
return v