admin
2025-04-08 c2aec8ae6367a41bb3cf4176a95500d433b8450e
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
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
"""
该模块下进行指数行情策略的编写
"""
import copy
# import decimal
import datetime
import json
import time
 
import constant
from log_module import async_log_util
from log_module.log import logger_common, logger_Overall_market_strength_score
# import time
# 引入掘金API
# from gm.api import *
from strategy import basic_methods, kpl_api
from strategy import data_cache
 
from utils import tool, juejin_api
 
# 获取logger实例
logger = logger_common
 
# ======================
# 模拟数据生成(完整版)
# ======================
# data = {
#     'total_stocks': 5000,  # 全市场股票总数
#     'limit_up': 120,  # 涨停股数量
#     'limit_down': 5,  # 跌停股数量
#     'advance_count': 2800,  # 上涨家数
#     'decline_count': 1500,  # 下跌家数
#     'high_retreat_count': 30,  # 当日回撤超10%的个股数量
#     'turnover': 1.2e12,  # 当日成交额(元)
#     'turnover_prev_day': 1.0e12,  # 前一日成交额
#     'northbound_inflow': 8e9,  # 北向资金净流入(元)
#     'max_northbound_30d': 15e9,  # 近30日最大北向净流入
#     'margin_buy': 8e10,  # 融资买入额
#     'sector_gains': [3.5, 2.8, 1.9, -0.5],  # 前4大板块涨幅(%)
#     'max_continuous_boards': 7,  # 最高连板数(如7连板)
#     'continuous_boards': [7, 5, 3, 2],  # 连板梯队(各层级连板数量)
# }
#
#
# # ======================
# # 因子计算与标准化处理
# # ======================
# def calculate_factors(data):
#     factors = {}
#
#     # === 新增核心因子 ===
#     # 1. 涨跌家数比(0-100分)
#     if data['decline_count'] == 0:
#         factors['advance_ratio'] = 100.0
#     else:
#         factors['advance_ratio'] = min(
#             (data['advance_count'] / data['decline_count']) * 50,  # 比值1:2对应100分
#             100.0
#         )
#
#     # 2. 涨停强度(标准化到0-100)
#     factors['limit_strength'] = (
#             (data['limit_up'] - data['limit_down']) / data['total_stocks'] * 1000  # 放大差异
#     )
#
#     # 3. 大幅回撤比例(0-100分)
#     factors['high_retreat_ratio'] = (
#             data['high_retreat_count'] / data['total_stocks'] * 1000  # 千分比更敏感
#     )
#
#     # 4. 连板高度与梯队(根据历史极值归一化)
#     factors['max_continuous'] = (
#             data['max_continuous_boards'] / 10 * 100  # 假设历史最高10连板
#     )
#     factors['board_ladder'] = (
#             len(data['continuous_boards']) / 5 * 100  # 假设最多5个连板层级
#     )
#
#     # === 原有因子优化 ===
#     # 5. 量能变化(成交额增长率)
#     turnover_growth = (
#             (data['turnover'] - data['turnover_prev_day']) /
#             data['turnover_prev_day'] * 100
#     )
#     factors['liquidity'] = turnover_growth
#
#     # 6. 板块强度(前3板块平均涨幅)
#     top_sectors = sorted(data['sector_gains'], reverse=True)[:3]
#     sector_avg = sum(top_sectors) / len(top_sectors)
#
#     factors['sector_strength'] = ((sector_avg - (-5.0)) / (10.0 - (-5.0)) * 100)  # 历史范围-5%~10%
#     # 7. 北向资金强度
#     factors['northbound_ratio'] = (data['northbound_inflow'] / data['max_northbound_30d'] * 100)
#
#     # 8. 融资买入占比
#     factors['margin_ratio'] = (data['margin_buy'] / data['turnover'] * 100)
#
#     # # 强制所有因子在0-100范围内
#     for key in factors:
#         factors[key] = max(0.0, min(factors[key], 100.0))
#
#     return factors
#
#
# # ======================
# # 权重分配(总权重1.0)
# # ======================
# def get_weights():
#     return {
#         # 新增因子权重
#         'advance_ratio': 0.15,  # 涨跌家数比
#         'limit_strength': 0.2,  # 涨停强度
#         'high_retreat_ratio': 0.1,  # 大幅回撤
#         'max_continuous': 0.1,  # 连板高度
#         'board_ladder': 0.05,  # 连板梯队
#         # 原有因子权重
#         'liquidity': 0.15,  # 量能变化
#         'sector_strength': 0.1,  # 板块强度
#         'northbound_ratio': 0.1,  # 北向资金
#         'margin_ratio': 0.05  # 融资买入
#     }
#
#
# # ======================
# # 综合强度分数计算(含动态修正)
# # ======================
# def composite_strength_score(data):
#     factors = calculate_factors(data)
#     weights = get_weights()
#
#     # 基础加权得分
#     score = sum(factors[key] * weights[key] for key in factors)
#
#     # === 动态修正规则 ===
#     # 规则1:涨停数量超过100家时额外加分
#     if data['limit_up'] > 100:
#         score += min((data['limit_up'] - 100) * 0.2, 10)  # 最多加10分
#
#     # 规则2:连板梯队断裂时扣分(如最高板与次高板差距≥3)
#     continuous_boards = sorted(data['continuous_boards'], reverse=True)
#     if len(continuous_boards) >= 2 and (continuous_boards[0] - continuous_boards[1] >= 3):
#         score -= 15  # 梯队断裂惩罚
#
#     # 规则3:北向资金与涨跌家数背离时调整
#     if (factors['northbound_ratio'] > 50) and (factors['advance_ratio'] < 40):
#         score *= 0.9  # 权重股拉升导致的虚假繁荣
#
#     return max(0.0, min(score, 100.0))
 
 
# ======================
# 执行计算与结果输出
# ======================
# final_score = composite_strength_score(data)
# print("=== 综合强度分数 ===")
# print(f"当前得分: {final_score:.1f}/100")
#
# # 输出因子贡献度分析
# factors = calculate_factors(data)
# weights = get_weights()
# print("\n=== 因子贡献度明细 ===")
# for key in factors:
#     print(f"{key:20s}: {factors[key]:5.1f} × {weights[key]:.0%} = {factors[key] * weights[key]:5.1f}")
 
''' 代码输出示例:
=== 综合强度分数 ===
当前得分: 78.4/100
 
=== 因子贡献度明细 ===
advance_ratio        :  93.3 × 15% = 14.0
limit_strength       :  23.0 × 20% =  4.6
high_retreat_ratio   :   6.0 × 10% =  0.6
max_continuous       :  70.0 × 10% =  7.0
board_ladder         :  80.0 ×  5% =  4.0
liquidity            :  20.0 × 15% =  3.0
sector_strength      :  60.0 × 10% =  6.0
northbound_ratio     :  53.3 × 10% =  5.3
margin_ratio         :  10.0 ×  5% =  0.5
'''
 
 
# 指数行情策略函数
def instant_trend_strategy(current_info):
    len_current_info = len(current_info)
    # 初始化 index_K_line 字典,后期加上日期属性,每日分行写入本地JSONL文件中
    index_K_line = {
        'Shanghai': {},
        'Shenzhen': {},
        'TSXV': {}
    }
    if current_info is not None and len_current_info > 0:
        # print(f"current_info------------{current_info}")
        # 上证指数数据
        Shanghai_index_data = current_info.get('000001')
        Shanghai_index = Shanghai_index_data[0]  # 上证指数
        Shanghai_index_volume = round(Shanghai_index_data[1]/100000000, 2)  # 上证指数 当日当时成交量
        Shanghai_index_turnover = round(Shanghai_index_data[2]/100000000, 2)  # 上证指数 当日当时成交额度
        Shanghai_Yesterday_closing_index = round(Shanghai_index_data[3], 2)  # 上证指数 昨日收盘指数
        logger.info(f"上证 指数:{Shanghai_index}   昨日收盘指数:{Shanghai_Yesterday_closing_index}   成交量:{Shanghai_index_volume}亿 手   成交额:{Shanghai_index_turnover}亿 元")
 
        # 深证指数数据
        Shenzhen_index_data = current_info.get('399001')
        Shenzhen_index = Shenzhen_index_data[0]  # 深证指数
        Shenzhen_index_volume = round(Shenzhen_index_data[1]/100000000, 2)  # 深证指数 当日当时成交量
        Shenzhen_index_turnover = round(Shenzhen_index_data[2]/100000000, 2)  # 深证指数 当日当时成交额度
        Shenzhen_Yesterday_closing_index = round(Shenzhen_index_data[3], 2)  # 深证指数 昨日收盘指数
        logger.info(f"深证 指数:{Shenzhen_index}   昨日收盘指数:{Shenzhen_Yesterday_closing_index}   成交量:{Shenzhen_index_volume}亿 手   成交额:{Shenzhen_index_turnover}亿 元")
 
        # 创业板指数数据
        TSXV_index_data = current_info.get('399006')
        TSXV_index = TSXV_index_data[0]  # 创业板指
        TSXV_index_volume = round(TSXV_index_data[1]/100000000, 2)  # 创业板指 当日当时成交量
        TSXV_index_turnover = round(TSXV_index_data[2]/100000000, 2)  # 创业板指 当日当时成交额度
        TSXV_Yesterday_closing_index = round(TSXV_index_data[3], 2)  # 深证指数 昨日收盘指数
        logger.info(f"创业板 指数:{TSXV_index}   昨日收盘指数:{TSXV_Yesterday_closing_index}  成交量:{TSXV_index_volume}亿 手   成交额:{TSXV_index_turnover}亿 元")
 
        # 调用涨幅公式计算对应的股票tick瞬时涨幅
        data_cache.Shanghai_tick_growth = basic_methods.tick_growth('000001', Shanghai_index)
        data_cache.Shanghai_today_growth = basic_methods.intraday_growth(Shanghai_index, Shanghai_Yesterday_closing_index)
        logger.info(f"上证指数 瞬时涨幅 ---- {round(data_cache.Shanghai_tick_growth, 4)}%")
        logger.info(f"上证指数 当日涨幅 ==== {round(data_cache.Shanghai_today_growth, 4)}%")
        # 调用涨幅公式计算对应的股票tick瞬时涨幅
        data_cache.Shenzhen_tick_growth = basic_methods.tick_growth('399001', Shanghai_index)
        data_cache.Shenzhen_today_growth = basic_methods.intraday_growth(Shenzhen_index, Shenzhen_Yesterday_closing_index)
        logger.info(f"深证指数 瞬时涨幅 ---- {round(data_cache.Shenzhen_tick_growth, 4)}%")
        logger.info(f"深证指数 当日涨幅 ==== {round(data_cache.Shenzhen_today_growth, 4)}%")
        # 调用涨幅公式计算对应的股票tick瞬时涨幅
        data_cache.TSXV_tick_growth = basic_methods.tick_growth('399006', Shanghai_index)
        data_cache.TSXV_today_growth = basic_methods.intraday_growth(TSXV_index, TSXV_Yesterday_closing_index)
        logger.info(f"创业板指 瞬时涨幅 ---- {round(data_cache.TSXV_tick_growth, 4)}%")
        logger.info(f"创业板指 当日涨幅 ==== {round(data_cache.TSXV_today_growth, 4)}%")
 
        # 在集合竞价时更新一下 各个指数的开盘涨幅
        now_time = tool.get_now_time_str()
        # 9:25:06 < now_time < 9:25:12 记录开盘指数 及 开盘涨幅
        if data_cache.LATER_OPEN_BIDDING_TIME < now_time < data_cache.AFTER_OPEN_BIDDING_TIME:
            index_K_line['Shanghai']['Shanghai_open_index'] = Shanghai_index
            index_K_line['Shenzhen']['Shenzhen_open_index'] = Shenzhen_index
            index_K_line['TSXV']['TSXV_open_index'] = TSXV_index
            data_cache.Shanghai_open_growth = data_cache.Shanghai_today_growth
            data_cache.Shenzhen_open_growth = data_cache.Shenzhen_today_growth
            data_cache.TSXV_open_growth = data_cache.TSXV_today_growth
 
        # 15:00:00 < now_time < 15:01:00  记录收盘指数
        if data_cache.CLOSING_TIME < now_time < data_cache.AFTER_CLOSING_TIME:
            index_K_line['Shanghai']['Shanghai_close_index'] = Shanghai_index
            index_K_line['Shenzhen']['Shenzhen_close_index'] = Shenzhen_index
            index_K_line['TSXV']['TSXV_close_index'] = TSXV_index
 
        logger.info(f"上证指数 开盘涨幅 ==== {round(data_cache.Shanghai_open_growth, 4)}%")
        logger.info(f"深证指数 开盘涨幅 ==== {round(data_cache.Shenzhen_open_growth, 4)}%")
        logger.info(f"创业板指 开盘涨幅 ==== {round(data_cache.TSXV_open_growth, 4)}%")
 
 
# 大盘指数趋势预期函数(用于对大盘开盘后短期内的趋势预测)
def index_trend_expectation():
    index_trend_expectation_score = 100
    # 判断三大指数开盘涨幅 预期
    if data_cache.Shanghai_open_growth > 0 and data_cache.Shenzhen_open_growth > 0 and data_cache.TSXV_open_growth > 0:
        index_composite_open_increase = '三大指数:高开'
        index_trend_expectation_score += 5
        if data_cache.Shanghai_open_growth >= 1 and data_cache.Shenzhen_open_growth >= 1 and data_cache.TSXV_open_growth >= 1:
            index_composite_open_increase = '三大指数:高开1% 以上'
            index_trend_expectation_score += 5
    elif data_cache.Shanghai_open_growth < 0 and data_cache.Shenzhen_open_growth < 0 and data_cache.TSXV_open_growth < 0:
        index_composite_open_increase = '三大指数:低开'
        index_trend_expectation_score -= 5
        if data_cache.Shanghai_open_growth <= 1 and data_cache.Shenzhen_open_growth <= 1 and data_cache.TSXV_open_growth <= 1:
            index_composite_open_increase = '三大指数:低开1% 以下'
            index_trend_expectation_score -= 5
    else:
        index_composite_open_increase = '三大指数:涨跌不一'
    logger.info(f"开盘指数开盘涨幅播报:{index_composite_open_increase}")
 
    # 判断三大指数开盘后当日涨幅 预期
    if data_cache.Shanghai_today_growth > data_cache.Shanghai_open_growth and data_cache.Shenzhen_today_growth > data_cache.Shenzhen_open_growth and data_cache.TSXV_today_growth > data_cache.TSXV_open_growth:
        index_composite_today_increase = '三大指数:短期高走'
        index_trend_expectation_score += 10
    elif data_cache.Shanghai_today_growth < data_cache.Shanghai_open_growth and data_cache.Shenzhen_today_growth < data_cache.Shenzhen_open_growth and data_cache.TSXV_today_growth < data_cache.TSXV_open_growth:
        index_composite_today_increase = '三大指数:短期低走'
        index_trend_expectation_score -= 10
    else:
        index_composite_today_increase = '三大指数:短期走势不一'
    logger.info(f"开盘指数开盘短期走势播报:{index_composite_today_increase}")
 
    # 判断三大指数开盘涨幅 预期
    if data_cache.Shanghai_tick_growth > 0 and data_cache.Shenzhen_tick_growth > 0 and data_cache.TSXV_tick_growth > 0:
        index_composite_tick_increase = '三大指数:瞬时高走'
        index_trend_expectation_score += 2
        if data_cache.Shanghai_tick_growth >= 0.01 and data_cache.Shenzhen_tick_growth >= 0.01 and data_cache.TSXV_tick_growth >= 0.01:
            index_composite_tick_increase = '三大指数:高走0.01% 以上'
            index_trend_expectation_score += 4
    elif data_cache.Shanghai_tick_growth < 0 and data_cache.Shenzhen_tick_growth < 0 and data_cache.TSXV_tick_growth < 0:
        index_composite_tick_increase = '三大指数:瞬时低走'
        index_trend_expectation_score -= 2
        if data_cache.Shanghai_tick_growth <= 0.01 and data_cache.Shenzhen_tick_growth <= 0.01 and data_cache.TSXV_tick_growth <= 0.01:
            index_composite_tick_increase = '三大指数:低走0.01% 以下'
            index_trend_expectation_score -= 4
    else:
        index_composite_tick_increase = '三大指数:涨跌不一'
    logger.info(f"开盘指数开盘瞬时走势播报:{index_composite_tick_increase}")
    if index_trend_expectation_score > 100:
        index_trend_expectation_score = 100
    return index_trend_expectation_score
 
 
# 获取指数K线并写入本地的函数
def get_index_K_line():
    all_index_K_line_dict = {}
    for i in data_cache.INDEX_SYMBOL_LIST:
        index_K_line = juejin_api.JueJinApi.history_n(i, "1d", 90, 1, "open,close,high,low,amount,volume,bob")
        # print(f"index_K_line=={index_K_line}")
        all_index_K_line_dict[i] = index_K_line
    # print(f"all_index_K_line=={all_index_K_line_dict}")
    return all_index_K_line_dict
 
 
# 给指数K线加入属性值
def get_property_mark(it_K_line, symbol):
    historical_high_price = 0.01  # 初始化历史最高价
    historical_low_price = 0.01  # 初始化历史最低价
    historical_low_price_index = 0  # 初始化历史最高价序号
    historical_high_price_index = 0  # 初始化历史最低价序号
    historical_average_price = 0.01  # 初始化历史均价
    large_amplitude_day = []  # 初始化大幅震荡日期
    current_count = 0  # 当前连续满足条件的天数
    start = None
    results = []
    dates_list = []
 
    for i in range(0, len(it_K_line) - 1):
        previous_close = it_K_line[i + 1]['close']  # 昨日收盘价
        previous_high = it_K_line[i + 1]['high']  # 昨日最高价
        current_open = round(it_K_line[i]['open'], 2)  # 当日开盘价
        current_close = round(it_K_line[i]['close'], 2)  # 当日收盘价
        current_high = round(it_K_line[i]['high'], 2)  # 当日最高价
        current_low = round(it_K_line[i]['low'], 2)  # 当日最低价
        limit_up_price = basic_methods.limit_up_price(previous_close)  # 计算出的当天涨停价
        limit_up_price = float(limit_up_price)  # 将涨停价转化为浮点
        limit_down_price = basic_methods.limit_down_price(previous_close)  # 计算出的当天跌停价
        limit_down_price = float(limit_down_price)  # 将跌停价转化为浮点
        current_today_volume = it_K_line[i]['volume']  # 当日总交易量
        current_yesterday_volume = it_K_line[i + 1]['volume']  # 昨日总交易量
        # current_today_amount = it_K_line[i]['amount'] #当日总交易额
        current_today_growth = basic_methods.intraday_growth(current_close, previous_close)  # 计算出当日涨幅
        it_K_line[i]['today_growth'] = current_today_growth  # 将当日涨幅数据添加到字典中对应的日期中
        current_today_amplitude = round((current_high - current_low) / previous_close, 2)  # 计算出当日振幅
        it_K_line[i]['today_amplitude'] = current_today_amplitude  # 将当日振幅数据添加到字典中对应的日期中
        historical_high_price = round(max(i['high'] for i in it_K_line), 2)  # 计算出历史最高价
        historical_high_price_index = max(range(len(it_K_line)), key=lambda ii: it_K_line[ii]['high'])  # 找到最高价的索引
        historical_low_price = round(min(i['low'] for i in it_K_line), 2)  # 计算出历史最低价
        historical_low_price_index = min(range(len(it_K_line)), key=lambda ii: it_K_line[ii]['low'])  # 找到最低价的索引
        historical_average_price = round((historical_high_price + historical_low_price) / 2, 2)  # 计算出历史最均价
        # 把最高价、最高价序号、最低价、最低价序号,添加到K线的昨日字典中
        new_properties = {
            'historical_high_price': historical_high_price,
            'historical_high_price_index': historical_high_price_index,
            'historical_low_price': historical_low_price,
            'historical_low_price_index': historical_low_price_index,
            'historical_average_price': historical_average_price
        }
        it_K_line[0].update(new_properties)
 
        # 计算大振幅的日期并添加到大振幅日期列表中
        if not (-1 < it_K_line[i]['today_growth'] < 1):
            large_amplitude_day.append(it_K_line[i]['bob'])
 
        # 判断K线图形风险位置 及 高低时间点
        if historical_low_price_index > historical_high_price_index:
            # 序列小于1是历史最高价  历史长度90,其实还可以根据更长来判断更显程度,历史长度很短的一般认为具有更高风险,而更长的之前有可能有更高的历史高位还比较远
            # 最低价在前
            it_K_line[0]['risk_position'] = 'low_price_ahead'
            '''
            以下部分条件分支由于都是对 it_K_line[0]['risk_position'] 数据进行修改,
            条件判断逻辑有部分重叠,所以应按照逻辑的覆盖面进行先后判断,避免先把大部分过滤掉了。
            所以当前条件分支语句的顺序不要轻易更换。
            # [(historical_high_price / round(it_K_line[0]['close'], 2) < 1.05)的预设值取值范围选择其一:
            # {"均价以上近前高的开盘价":1.05,"接近前高 的跌停价":1.11,"接近前高 的一个炸板加一个跌停的收盘价":1.17,"均价与最高价之间的涨停价":1.21,"均价与最高价之间的价":1.33}
            '''
            # 最高位据昨日较远 且 昨收价距历史均价差距较小 且 整体涨跌幅度较大 且 最高位 与 最低位为三倍涨幅的妖股【当前二度试探风险】
            if (2 < historical_high_price_index < 15 and len(it_K_line) >= 90) and (
                    (historical_average_price / round(it_K_line[0]['close'], 2)) < 2) and (
                    historical_high_price > historical_low_price * 3):
                it_K_line[0]['risk_position'] = 'recent_monster_second_break_risk'
            # 最高位据昨日较远 且 昨收价距历史均价差距较小 且 整体涨跌幅度较大 【当前二度突破风险】
            if (2 < historical_high_price_index < 15 and len(it_K_line) >= 90) and (
                    (historical_average_price / round(it_K_line[0]['close'], 2)) < 1.17) and (
                    historical_high_price > historical_low_price * 1.8):
                it_K_line[0]['risk_position'] = 'recent_second_break_risk'
            # 最高位据昨日较远 且 昨收价距历史最高价差距较小(小于5%,涨幅5%是左右是最容易把低吸骗进去的日内涨幅) 且 整体涨跌幅度较大  【当前二度突破近前高风险】
            # 【双成药业 2024-11-08 这样的二次近前高,实际数值为1.4646...,为安全起见还是设置为1.5】
            if (2 < historical_high_price_index < 15 and len(it_K_line) >= 90) and (
                    historical_high_price / round(it_K_line[0]['close'], 2) < 1.5) and (
                    historical_high_price > historical_low_price * 1.8):
                it_K_line[0]['risk_position'] = 'recent_second_break_near_high_position_risk'
            # 昨日就是最高位 且 整体涨跌幅度较大 【当前高位风险】
            if (historical_high_price_index < 2 and len(it_K_line) >= 90) and (
                    historical_high_price > historical_low_price * 1.8):
                it_K_line[0]['risk_position'] = 'recent_high_position_risk'
        else:
            # 最高价在前
            it_K_line[0]['risk_position'] = 'high_price_ahead'
            # 最低位据昨日较远 且 昨收价距历史均价差距较小 且 整体涨跌幅度较大 【当前二度崩溃风险】
            if (2 < historical_low_price_index < 15 and len(it_K_line) >= 90) and (
                    (historical_average_price / round(it_K_line[0]['close'], 2)) > 1.1):
                it_K_line[0]['risk_position'] = 'recent_second_crash_risk'
            # 昨日就是最低位 且 整体涨跌幅度较大 【当前低位风险】
            if (historical_low_price_index < 2 and len(it_K_line) >= 90) and (
                    historical_high_price > historical_low_price * 1.5):
                it_K_line[0]['risk_position'] = 'recent_low_position_risk'
 
        # 判断K线图形中连续低涨幅天数及具体序列号并把共识价格均价写入文件【阶段性价格共识位置】
        if 0 < it_K_line[i]['today_amplitude'] < 0.025 and i < 60 and (
                historical_high_price > historical_low_price * 1.5):
            if current_count == 0:
                start = i
            # 如果当前涨幅小于阈值,增加连续天数计数器
            current_count += 1
            # 如果循环复合条件的连续天数达到5天,记录起始索引
            if current_count > 5:
                # 检查 results 是否为空或当前序列不与最后一个序列重叠
                if not results or results[-1][1] < start:
                    if 0.98 < it_K_line[i]['high'] / it_K_line[start]['low'] < 1.02:
                        # 没有重叠,直接添加【其中start为循环到起始序号,i为循环到的结束序号。在实际的日期中要反过来】
                        results.append((start, i))
                        # 算出价格共识区间的均价
                        average_consensus_price = round((it_K_line[i]['high'] + it_K_line[start]['low']) / 2, 2)
                        dates_list.append((
                            it_K_line[start]['bob'].strftime('%Y-%m-%d %H:%M:%S'),
                            it_K_line[i]['bob'].strftime('%Y-%m-%d %H:%M:%S'),
                            average_consensus_price))
                        # if len(dates_list) > 1:  # 如果只需要检测包含多段价格共识区
                        it_K_line[0]['rise_and_fall_is_small_start_and_end_date'] = dates_list
        else:
            # 重置计数器
            current_count = 0
            start = None
        #  确保不会出现除以零的报错
        if current_yesterday_volume != 0:
            if str(it_K_line[i]['bob']).find('2025-03-21')>=0:
                print(f"")
            print(f"{it_K_line[i]['bob']} 的 current_today_volume=={current_today_volume},, current_yesterday_volume=={current_yesterday_volume}")
            if round(current_today_volume / current_yesterday_volume, 2) > 1.1:
                # print(f"i=={i} {it_K_line[i]['bob']} {round(current_today_volume/current_yesterday_volume,2)} 【放量】")
                if current_today_growth > 0:
                    it_K_line[i]['today_volume_shape'] = 'increases_up'
                    # print(f"i=={i}  {it_K_line[i]['bob']}   【放量上涨】")
                elif current_today_growth < 0:
                    it_K_line[i]['today_volume_shape'] = 'increases_down'
                    # print(f"i=={i}  {it_K_line[i]['bob']}   【放量下跌】")
                else:
                    it_K_line[i]['today_volume_shape'] = 'increases_balance'
                    # print(f"i=={i}  {it_K_line[i]['bob']}   【放量平收】")
 
            elif round(current_today_volume / current_yesterday_volume, 2) < 0.9:
                # print(f"i=={i} {it_K_line[i]['bob']} {round(current_today_volume/current_yesterday_volume,2)} 【缩量】")
                if current_today_growth > 0:
                    it_K_line[i]['today_volume_shape'] = 'decreases_up'
                    # print(f"i=={i}  {it_K_line[i]['bob']}   【缩量上涨】")
                elif current_today_growth < 0:
                    it_K_line[i]['today_volume_shape'] = 'decreases_down'
                    # print(f"i=={i}  {it_K_line[i]['bob']}   【缩量下跌】")
                else:
                    it_K_line[i]['today_volume_shape'] = 'decreases_balance'
                    # print(f"i=={i}  {it_K_line[i]['bob']}   【缩量平收】")
            else:
                # print(f"i=={i} {it_K_line[i]['bob']} {round(current_today_volume/current_yesterday_volume,2)} 【平量】")
                if current_today_growth > 0:
                    it_K_line[i]['today_volume_shape'] = 'remained_up'
                    # print(f"i=={i}  {it_K_line[i]['bob']}   【平量上涨】")
                elif current_today_growth < 0:
                    it_K_line[i]['today_volume_shape'] = 'remained_down'
                    # print(f"i=={i}  {it_K_line[i]['bob']}   【平量下跌】")
                else:
                    it_K_line[i]['today_volume_shape'] = 'remained_balance'
                    # print(f"i=={i}  {it_K_line[i]['bob']}   【平量平收】")
        else:
            logger.info(f"{symbol} 的 昨日成交量 为 0,报错!!")
 
        if current_open - previous_close > 0:
            # print(f"i=={i}  {it_K_line[i]['bob']} 成交总量:{today_volume},,,成交总金额:{today_amount}")
            # difference = current_close - previous_close
            if current_close - current_open > 0:
                it_K_line[i]['attribute'] = 'up_up'
                # print(f"i=={i}  {it_K_line[i]['bob']} 高开高走 【昨收价:{previous_close}  收盘价:{current_close}】")
            else:
                it_K_line[i]['attribute'] = 'up_down'
                # print(f"i=={i}  {it_K_line[i]['bob']} 高开低走 【昨收价:{previous_close}  收盘价:{current_close}】")
        else:
            if current_close - current_open > 0:
                it_K_line[i]['attribute'] = 'down_up'
                # print(f"i=={i}  {it_K_line[i]['bob']} 低开高走 【昨收价:{previous_close}  收盘价:{current_close}】")
            else:
                it_K_line[i]['attribute'] = 'down_down'
                # print(f"i=={i}  {it_K_line[i]['bob']} 低开低走 【昨收价:{previous_close}  收盘价:{current_close}】")
 
    # 将高涨跌幅日期打印出来
    # it_K_line[0]['large_amplitude_day'] = large_amplitude_day
 
    # 判断K线图形长期振幅 及 当前走势 【根据大振幅天数 反推算出 长期低幅度震荡持平、上涨、下跌的个股写入字典】
    if len(large_amplitude_day) < 1:
        # 长期低幅度震荡
        it_K_line[0]['long_term_amplitude'] = 'low_amplitude_oscillation'
        # it_K_line[0]['large_amplitude_day_len'] = len(large_amplitude_day)
        if (historical_high_price / historical_low_price) < 1.15:
            if 0.99 < (historical_average_price / round(it_K_line[0]['close'], 2)) < 1.09:
                # 长期低幅度震荡持平
                it_K_line[0]['long_term_amplitude'] = 'low_amplitude_oscillation_remains_stable'
        else:
            if (historical_low_price_index > historical_high_price_index) and (
                    historical_high_price_index < 2 and len(it_K_line) > 88):
                # 长期低幅度震荡上涨
                it_K_line[0]['long_term_amplitude'] = 'low_amplitude_oscillation_and_rise'
            elif (historical_low_price_index < historical_high_price_index) and (
                    historical_low_price_index < 2 and len(it_K_line) > 88):
                # 长期低幅度震荡下跌
                it_K_line[0]['long_term_amplitude'] = 'low_amplitude_oscillation_and_decline'
 
 
# 将加入属性值的指数K线下入到本地文件中
def all_index_k_line_dict_write():
    all_index_K_line_dict = get_index_K_line()
    # 初始化所有个股的指标K线列表
    all_index_k_line_property_dict = {}
    for i in data_cache.INDEX_SYMBOL_LIST:
        # print(f"i==========={i}")
        i_k_line = all_index_K_line_dict[i]  # 获取i的K线
        i_k_line_copy = copy.deepcopy(i_k_line)  # 深拷贝i的K线
        it_K_line_reversed = list(reversed(i_k_line_copy))  # 开盘啦获取的数据需要反转i的K线
        if not it_K_line_reversed:
            continue
        get_property_mark(it_K_line_reversed, i)  # 给标的的K线更新指标属性 把股票代码同时传给要调用的函数
        symbol_K_line_property_dict = {i: it_K_line_reversed}  # 添加 更新极限指标属性的K线 字典
        # print(f"symbol_K_line_property_dict===={symbol_K_line_property_dict}")
        all_index_k_line_property_dict.update(symbol_K_line_property_dict)
    # print(f"all_index_k_line_property_dict===={all_index_k_line_property_dict}")
 
    # 构造时间格式datetime转化为字符串,以便将K线属性指标转化为json格式写入本地文件
    def convert_datetime(obj):
        if isinstance(obj, datetime.datetime):
            return obj.strftime('%Y-%m-%d %H:%M:%S')  # 转换为字符串
        elif isinstance(obj, dict):
            return {k: convert_datetime(v) for k, v in obj.items()}  # 递归处理字典
        elif isinstance(obj, list):
            return [convert_datetime(element) for element in obj]  # 递归处理列表
        # 可以添加其他类型的处理逻辑
        else:
            # 对于未知类型,你可以选择保留原样、跳过或引发异常
            # 这里我们选择保留原样
            return obj
 
    try:
        json_data = json.dumps(convert_datetime(all_index_k_line_property_dict), ensure_ascii=False, indent=4)
        # 将转换后的JSON字符串写入文件
 
        with open(constant.INDEX_K_BARS_PATH, 'w', encoding='utf-8') as f:
            f.write(json_data)
        # print(f"json_data:{json_data}")
    except Exception as error:
        print(f"An error occurred while converting the data to JSON: {error}")
    logger.info(f"加属性的指数k线写完了!{tool.get_now_time_str()}")
 
 
# 获取实时大盘行情情绪综合强度 [分数] 函数 并 计算当日计划持仓数量
def get_real_time_market_strong():
    while True:
        try:
            if data_cache.position_automatic_management_switch is True:
                now_time = tool.get_now_time_str()
                if data_cache.L1_DATA_START_TIME < now_time < data_cache.CLOSING_TIME:
                    # 获取大盘综合强度分数
                    data_cache.real_time_market_strong = kpl_api.get_market_strong()
                    # 获取市场情绪字典【完整】,并整理
                    data_cache.real_time_market_sentiment_dirt = kpl_api.changeStatistics()
                    date_today = data_cache.real_time_market_sentiment_dirt.get(['Day'], None)
                    significant_drawdown = data_cache.real_time_market_sentiment_dirt.get(['df_num'], None)
                    sentiment_indicators = data_cache.real_time_market_sentiment_dirt.get(['ztjs'], None)
                    limit_up_amount = data_cache.real_time_market_sentiment_dirt.get(['ztjs'], None)
                    connecting_board_height = data_cache.real_time_market_sentiment_dirt.get(['lbgd'], None)
                    # 获取市场情绪-涨跌统计
                    data_cache.rise_and_fall_statistics_dirt = kpl_api.getMarketFelling()
                    limit_up_numbers = data_cache.rise_and_fall_statistics_dirt.get(['ZT', None])
                    actual_limit_up_numbers = data_cache.rise_and_fall_statistics_dirt.get(['SJZT', None])
                    ST_limit_up_numbers = data_cache.rise_and_fall_statistics_dirt.get(['STZT', None])
                    limit_down_numbers = data_cache.rise_and_fall_statistics_dirt.get(['DT', None])
                    actual_limit_down_numbers = data_cache.rise_and_fall_statistics_dirt.get(['SJDT', None])
                    ST_limit_down_numbers = data_cache.rise_and_fall_statistics_dirt.get(['STDT', None])
 
                    rise_numbers = data_cache.rise_and_fall_statistics_dirt.get(['SZJS', None])
                    fall_numbers = data_cache.rise_and_fall_statistics_dirt.get(['XDJS', None])
 
                    # 该logger.info的的日志不再需要打印,后续将转入到GUI客户端上直接显示,该数据的打印交由下方的打印机制异步执行单独存储,以便后续可视化呈现后进行更高效的数据分析
                    # logger.info(f"大盘行情情绪综合强度 [分数]==={data_cache.real_time_market_strong}分")
                    if data_cache.MORN_MARKET_CLOSING_TIME < now_time < data_cache.NOON_MARKET_OPENING_TIME:
                        pass
                        logger.info(f"午间休市时间内 不打印大盘综合强度分数")
                    else:
                        # 大盘综合强度分数 的 异步日志
                        # logger_Overall_market_strength_score.info(data_cache.real_time_market_strong)
                        async_log_util.info(logger_Overall_market_strength_score, f"{data_cache.real_time_market_strong}")
                        logger.info(f"日期:{date_today},情绪指标:{sentiment_indicators}分,大幅回撤:{significant_drawdown},涨停家数:{limit_up_amount},连板高度:{connecting_board_height}")
                        logger.info(f"上涨家数:{rise_numbers}分,下跌家数:{fall_numbers},实际涨停家数:{actual_limit_up_numbers},实际跌停家数:{actual_limit_down_numbers}")
                        logger.info(f"涨跌统计字典{data_cache.rise_and_fall_statistics_dirt}")
 
                    usefulMoney = data_cache.account_finance_dict[0].get('usefulMoney', 0)
                    logger.info(f"账户可用资金==={usefulMoney}元")
                    # 低迷情绪比例
                    low_emotion_mood_ratio = 1
                    # 33分是个两级分化阶梯不好,目前不好拿捏,暂时不用
                    # if data_cache.real_time_market_strong <= 33:
                    if data_cache.real_time_market_strong < 30:
                        # 如果大盘综合强度分数小于30,将低迷情绪分数比例设置为0.01,可用资金缩小一百倍
                        low_emotion_mood_ratio = 0.01
                        if data_cache.real_time_market_strong <= 10:
                            low_emotion_mood_ratio = 0
                    logger.info(f"极端低迷情绪比例===={low_emotion_mood_ratio * 100}%")
 
                    data_cache.index_trend_expectation_score = index_trend_expectation()
                    logger.info(f"大盘指数情绪预期分数==={data_cache.index_trend_expectation_score}分")
                    print(f"大盘指数情绪预期分数==={data_cache.index_trend_expectation_score}分")
                    # # 目前大盘指数情绪预期分数 尚不科学 强制设置为初始0值
                    # index_trend_expectation_score = 0
 
                    # 获取计算今天新增的持仓数量
                    addition_position_number = len(data_cache.addition_position_symbols_set)
                    # 定义一个今日的剩余新增持仓数量的变量
                    Unfinished_opening_plan_number = 3 - addition_position_number
                    logger.info(f"今日的剩余新增持仓数量==={Unfinished_opening_plan_number}")
                    if Unfinished_opening_plan_number != 0:
                        # 如果GUI看盘上没有手动设置具体的下单金额,就按照评分策略的金额下单,否则就按照GUI设置的金额下单。
                        if data_cache.BUY_MONEY_PER_CODE < 0:
                            # 根据账户可用金额 计算今日计划下单金额
                            # 账户可用金额 默认乘以0.9,永远留一点钱,一方面也冗余一些计算误差
                            #  ((大盘综合强度分数 + 大盘指数情绪预期分数) * 0.01) * (账户可用金额 * 0.9 * 极端低迷情绪比例 / 今日最大新增持仓票数)
                            # data_cache.today_planned_order_amount = ((data_cache.real_time_market_strong + data_cache.index_trend_expectation_score) * 0.01) * (
                            #                                                 usefulMoney * 0.9 * low_emotion_mood_ratio / Unfinished_opening_plan_number)
                            data_cache.today_planned_order_amount = (usefulMoney * 0.95 * low_emotion_mood_ratio / Unfinished_opening_plan_number)
                            logger.info(f"采用开仓策略计算方式=》今日计划下单金额:{data_cache.today_planned_order_amount},")
                        else:
                            data_cache.today_planned_order_amount = data_cache.BUY_MONEY_PER_CODE
                            logger.info(f"采用GUI设置方式=》今日计划下单金额:{data_cache.today_planned_order_amount}")
 
        except Exception as error:
            logger_common.exception(error)
            logger.error(f"获取实时大盘行情情绪综合强度[分数] 函数报错: {error}")
        finally:
            time.sleep(3)
 
 
if __name__ == '__main__':
    # market_strong = kpl_api.get_market_strong()
    # print(f"{market_strong}")
    get_real_time_market_strong()
    # all_index_K_line_dict = get_index_K_line()
 
    # all_index_k_line_dict_write()
    # print(f"指数K线{data_cache.all_index_k_line_property_dict}")
    # all_index_k_line_dict_write()