admin
2025-02-27 5de42b1ecdd324f9e728600ad8c57ab810a2db86
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
# coding=utf-8
from __future__ import print_function, absolute_import, unicode_literals
 
import decimal
 
from log_module.log import logger_common
# from datetime import datetime
from strategy import data_cache
from utils import hx_qc_value_util
 
# 获取logger实例
logger = logger_common
 
 
# 将纯数字代码转化为=》掘金格式股票代码
def format_stock_symbol(code):
    if code.startswith('6'):
        return "SHSE." + code
    elif code.startswith('0'):
        return "SZSE." + code
    elif code.startswith('2'):
        return "SZSE." + code
    elif code.startswith('3'):
        return "SZSE." + code
    else:
        print(f"这个代码有异常,无法处理{code}")
        return code
 
 
# 将掘金格式股票代码转化=》纯数字代码
def format_stock_code(symbol):
    stock_code = symbol.split('.')[1]  # 将symbol转为纯数字编号股票代码
    return stock_code
 
 
# 查询前N个交易日的具体交易日期函数:在调用时date_of_the_day应该传入当天日期,num是前跨天数。循环取值后 返回的date_of_the_day值就是目标具体的交易日期,
def pre_num_trading_day(date_of_the_day, num):
    for i in range(num):
        pre_date = hx_qc_value_util.get_previous_trading_date(date_of_the_day)  # 获取前一个交易日API
        date_of_the_day = pre_date
    return date_of_the_day
 
 
# 计算当日涨幅公式
def intraday_growth(price, pre_close):
    if price is not None and pre_close is not None:
        today_growth = (price - pre_close) / pre_close * 100  # 计算涨幅百分比
        today_growth = round(today_growth, 2)
        return today_growth
 
#
# open_growth = intraday_growth(10.75, 11.08)
# print(f"open_growth=={open_growth}")
 
 
# 计算瞬时涨幅公式
# 初始化历史价格
price_history = {}
 
 
def calculate_growth(symbol, price):
    try:
        if symbol not in price_history:
            return 0  # 不足两个历史价格,无法计算涨幅
        last_price = price_history[symbol]
        # print(f"price_history[symbol]~~~~~~~~~{price_history[symbol]}")
        if last_price != 0:
            growth = (price - last_price) / last_price * 100  # 计算涨幅百分比
            return growth
    finally:
        price_history[symbol] = price
        # print(f"price======={price}")
        # print(f"price_history=={price_history}")
        # print(f"price_history[symbol]=={price_history[symbol]}")
 
 
# 计算tick涨幅公式【为卖出策略单独创建函数】
# 初始化历史价格
history_price = {}
 
 
def tick_growth(symbol, price):
    try:
        if symbol not in history_price:
            return 0  # 不足两个历史价格,无法计算涨幅
        last_price = history_price[symbol]
        # print(f"last_price===={last_price}")
        if last_price != 0:
            growth = (price - last_price) / last_price * 100  # 计算涨幅百分比
            return growth
    finally:
        history_price[symbol] = price
        # print(f"price======={price}")
        # print(f"price_history=={price_history}")
        # print(f"price_history[symbol]=={price_history[symbol]}")
 
 
# 计算当日涨停价函数   形参pre_close  实参应传入 pre_close  【return的结果需要小数点后两位,在第三位进行四舍五入】
def limit_up_price(pre_close):
    limit_up_price_data = decimal.Decimal(str(pre_close)) * decimal.Decimal("1.1")
    limit_up_price_value = limit_up_price_data.quantize(decimal.Decimal("0.00"), decimal.ROUND_HALF_UP)
    return float(limit_up_price_value)
# 测试计算用
# limit_up = limit_up_price(15)
# print(f"limit_up=={limit_up}")
 
 
# 计算当日跌停价函数   形参pre_close  实参应传入 pre_close  【return的结果需要小数点后两位round取整】
def limit_down_price(pre_close):
    limit_down_price_data = decimal.Decimal(str(pre_close)) * decimal.Decimal("0.9")
    limit_down_price_value = limit_down_price_data.quantize(decimal.Decimal("0.00"), decimal.ROUND_HALF_UP)
    return float(limit_down_price_value)
# 测试计算用
# limit_down = limit_down_price(20)
# print(f"limit_up=={limit_down}")
 
 
# print(limit_up_price(24.95))
# print(calculate_growth("000333",54.3))
 
# 历史K线累计涨停天数函数
def count_limit_up_day(k_line_data):
    limit_up_day = 0  # 初始化涨停天数
    # 计算90天内涨停天数
    for i in k_line_data:
        if 'attribute' in i and (i['attribute'] in data_cache.limit_up_type):
            limit_up_day += 1
            # print(f"涨停提日期:{i['bob']}")
        # print(f"涨停天数----limit_up_day======{limit_up_day}")
    return limit_up_day
 
 
#  是否接近三种大抛压位计算函数
def position_of_throwing_pressure(k_line_data, current_open, current_volume, today_limit_up_price):
    """
    :param k_line_data:个股对应的K线属性数据
    :param current_open:个股当前最新价
    :param current_volume:个股当日当时交易量
    :param today_limit_up_price:个股当日涨停价
    :return:是否接近涨停抛压位,是否接近炸板抛压位,是否接近跌停抛压位,
    """
    limit_up_throwing_pressure = False
    frying_plate_throwing_pressure = False
    limit_down_throwing_pressure = False
    # 找到最近7日内的有涨停的序号
    limit_up_day_min_index = next((i for i, d in enumerate(k_line_data[0:7]) if 'attribute' in d and d['attribute'] in data_cache.limit_up_type), None)  # 如果没有找到,返回None
    # 找到最近7日内的有炸板的序号
    frying_plate_day_min_index = next((i for i, d in enumerate(k_line_data[0:7]) if 'attribute' in d and d['attribute'] in data_cache.frying_plate_type), None)  # 如果没有找到,返回None
    # 找到最近7日内的有跌停的序号
    limit_down_day_min_index = next((i for i, d in enumerate(k_line_data[0:7]) if 'attribute' in d and d['attribute'] in data_cache.limit_down_type), None)  # 如果没有找到,返回None
    # 最近的涨停序号存在 且 非昨日
    if limit_up_day_min_index is not None and limit_up_day_min_index > 0:
        # 开盘价 < 涨停当日最高价 <= 今日涨停价
        if current_open < k_line_data[limit_up_day_min_index]['high'] <= today_limit_up_price:
            # 涨停次日量 < 涨停当日量 * 1.2
            if k_line_data[limit_up_day_min_index - 1]['volume'] < k_line_data[limit_up_day_min_index]['volume'] * 1.2:
                # 涨停次日最高价 < 涨停当日最高价的1.02倍。
                if k_line_data[limit_up_day_min_index - 1]['high'] < k_line_data[limit_up_day_min_index]['high'] * 1.02:
                    logger.info(f"【{k_line_data[0]['sec_name']}】,涨停大抛压日期:{k_line_data[limit_up_day_min_index]['bob']}")
                    limit_up_throwing_pressure = True
    # 最近的炸板序号存在 且 非昨日
    if frying_plate_day_min_index is not None and frying_plate_day_min_index > 0:
        # 开盘价<炸板当日最高价<=今日涨停价 或 开盘价<炸板当日收盘价(基本意味着炸板当日的均价)<=今日涨停价 或 开盘价<炸板次日最高价<=今日涨停价
        if (current_open < k_line_data[frying_plate_day_min_index]['high'] <= today_limit_up_price) or (current_open < k_line_data[frying_plate_day_min_index]['close'] <= today_limit_up_price) or (current_open < k_line_data[frying_plate_day_min_index - 1]['high'] <= today_limit_up_price):
            # 炸板次日量 < 炸板当日量 * 1.2
            if k_line_data[frying_plate_day_min_index - 1]['volume'] < k_line_data[frying_plate_day_min_index]['volume'] * 1.2:
                # 炸板次日最高价 < 炸板当日最高价的1.02倍
                if k_line_data[frying_plate_day_min_index - 1]['high'] < k_line_data[frying_plate_day_min_index]['high'] * 1.02:
                    logger.info(f"【{k_line_data[0]['sec_name']}】,炸板大抛压日期:{k_line_data[frying_plate_day_min_index]['bob']},炸板次日量:{round(k_line_data[frying_plate_day_min_index - 1]['volume']/1000000, 2)} 万手")
                    frying_plate_throwing_pressure = True
    # 最近的跌停序号存在 且 非昨日
    if limit_down_day_min_index is not None and limit_down_day_min_index > 0:
        # 开盘价 < 跌停当日最低价 <= 今日涨停价 或 开盘价 < 跌停当日最高价 <= 今日涨停价  或 开盘价 < 跌停当日收盘价 <= 今日涨停价
        if (current_open < k_line_data[limit_down_day_min_index]['low'] <= today_limit_up_price) or (current_open < k_line_data[limit_down_day_min_index]['high'] <= today_limit_up_price) or (current_open < k_line_data[limit_down_day_min_index - 1]['close'] <= today_limit_up_price):
            # 跌停次日量 < 跌停当日量
            if k_line_data[limit_down_day_min_index - 1]['volume'] < k_line_data[limit_down_day_min_index]['volume']:
                logger.info(f"【{k_line_data[0]['sec_name']}】,跌停大抛压日期:{k_line_data[limit_down_day_min_index]['bob']}")
                limit_down_throwing_pressure = True
    return limit_up_throwing_pressure, frying_plate_throwing_pressure, limit_down_throwing_pressure
 
 
# 安全交易量公式 用于计算不同时间段理论的安全交易量值
def secure_volume(now_date_time):
    # 定义时间段的开始和结束时间(使用字符串格式)
    time_slots = [
        (("09:30:00", "09:30:30"), 0.05),
        (("09:30:30", "09:31:00"), 0.08),
        (("09:31:00", "09:31:30"), 0.1),
        (("09:31:30", "09:32:00"), 0.15),
        (("09:32:00", "09:32:30"), 0.18),
        (("09:32:30", "09:33:00"), 0.2),
        (("09:33:00", "09:34:00"), 0.25),
        (("09:35:00", "10:40:00"), 0.3),
        (("09:40:00", "10:00:00"), 0.4),
        (("10:00:00", "11:00:00"), 0.6),
        (("11:00:00", "14:00:00"), 0.8),
        (("14:00:00", "15:00:00"), 1.2),
    ]
    # 将now格式化为字符串以便比较
    now_str = now_date_time.strftime("%H:%M:%S")
    # 遍历时间段,找到匹配的时间段并返回对应的交易量比
    for (start_str, end_str), ratio in time_slots:
        if start_str <= now_str < end_str:
            return ratio
            # 如果没有匹配的时间段,返回0
    return 0
 
 
# 示例使用
# now = datetime.now()
# print(f"secure_volume(now)=={secure_volume(now)}")
 
# 计算 委买和委卖的比例函数(获取买盘强度数据)【掘金数据结构】
def buying_and_selling_ratio(current_quotes):
    buying_strong = False
    if current_quotes[0]['bid_v'] > current_quotes[0]['ask_v'] and (
            current_quotes[0]['bid_v'] + current_quotes[1]['bid_v'] + current_quotes[2]['bid_v'] +
            current_quotes[3]['bid_v'] + current_quotes[4]['bid_v']) > (
            current_quotes[0]['ask_v'] + current_quotes[1]['ask_v'] + current_quotes[2]['ask_v'] +
            current_quotes[3]['ask_v'] + current_quotes[4]['ask_v']):
        buying_strong = True
    return buying_strong
 
 
# 计算 委买和委卖的比例函数(获取买盘强度数据)【华鑫数据结构】
# current_quotes_buy == [[23.25, 800], [23.24, 1100], [23.23, 1100], [23.22, 2200], [23.21, 2300]]
# current_quotes_sell == [[23.27, 500], [23.29, 200], [23.3, 6900], [23.31, 500], [23.32, 200]]
def get_buying_strength(current_quotes_buy, current_quotes_sell):
    buying_strong = False
    if current_quotes_buy[0][1] > current_quotes_sell[0][1] and (
            current_quotes_buy[0][1] + current_quotes_buy[1][1] + current_quotes_buy[2][1] +
            current_quotes_buy[3][1] + current_quotes_buy[4][1]) > (
            current_quotes_sell[0][1] + current_quotes_sell[1][1] + current_quotes_sell[2][1] +
            current_quotes_sell[3][1] + current_quotes_sell[4][1]):
        buying_strong = True
    return buying_strong
 
 
# 最大化资金利用率股数下单比例
def maximum_buying_ratio(today_addition_num):
    # 查询今日新增持仓数量  仅仅在本地测试时使用
    # today_addition_num = len(data_cache.addition_position_symbols_set)
    # 可用余额比例分配方法函数
    if today_addition_num < 1:
        buying_ratio = 0.25
    elif today_addition_num < 2:
        buying_ratio = 0.33
    elif today_addition_num < 3:
        buying_ratio = 0.5
    elif today_addition_num < 4:
        buying_ratio = 0.75
    else:
        buying_ratio = 0.01
    return buying_ratio