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
"""
激进买数据管理
"""
import json
 
import constant
import l2_data_util
from code_attribute import code_nature_analyse, code_volumn_manager, gpcode_manager
from code_attribute.code_l1_data_manager import L1DataManager
from db import redis_manager_delegate as redis_manager
from db.redis_manager_delegate import RedisUtils
from l2.l2_transaction_data_manager import BigOrderDealManager, HuaXinBuyOrderManager
from log_module import async_log_util
from log_module.log import logger_l2_radical_buy
from third_data import kpl_data_manager
from trade.buy_money_count_setting import RadicalBuyBlockCodeCountManager
from trade.trade_data_manager import RadicalBuyDealCodesManager
from utils import tool, global_util
 
 
class RadicalBuyDataManager:
    @classmethod
    def is_code_can_buy(cls, code, deal_codes=None, is_refered=False):
        """
        代码是否可以买(根据代码本身属性)
        @param deal_codes: 已经成交的代码
        @param is_refered: 是否是参考票
        @param code: 代码
        @param total_sell_volume: 总卖量
        @return: 是否可以买, 原因
        """
        k_format = code_nature_analyse.CodeNatureRecordManager().get_k_format_cache(code)
        if k_format:
            if not k_format[13]:
                return False, "近60个交易日无涨停"
            if k_format[14]:
                # 昨天炸板,一律不买
                return False, f"昨日炸板"
        # 获取涨停价
        price = gpcode_manager.get_limit_up_price_as_num(code)
        if not price:
            # 获取现价
            price = L1DataManager.get_l1_current_price(code)
        if price:
            if price < constant.MIN_CODE_RADICAL_BUY_PRICE or price > constant.MAX_CODE_RADICAL_BUY_PRICE:
                return False, "价格不满足需求"
        # 判断自由流通股本
        zyltgb = global_util.zyltgb_map.get(code)
        if zyltgb:
            zyltgb_as_yi = round(zyltgb / 100000000, 2)
            zylt_can_buy = False
            for zy in constant.RADICAL_BUY_ZYLTGB_AS_YI_RANGES:
                if zy[0] <= zyltgb_as_yi <= zy[1]:
                    zylt_can_buy = True
                    break
            if not zylt_can_buy:
                return False, "自由流通市值不满足扫的范围"
        # 判断昨日是否跌幅过大
        k_format = code_nature_analyse.CodeNatureRecordManager().get_k_format_cache(code)
        if k_format and len(k_format) > 12 and k_format[12]:
            return False, "上个交易日跌幅过大"
 
        if gpcode_manager.BlackListCodeManager().is_in_cache(code):
            if deal_codes is not None and code in deal_codes:
                pass
            else:
                # 拉黑且不是已经买入性质的拉黑
                return False, "已拉黑"
 
        if is_refered:
            # 参考票没有大单
            volume_rate = code_volumn_manager.CodeVolumeManager().get_volume_rate(code, with_info=False)
            if volume_rate is None:
                volume_rate = 0.5
            big_order_deal_enough = is_big_order_deal_enough(code, volume_rate)
            if not big_order_deal_enough[0] and big_order_deal_enough[2]:
                return False, "交易前两分钟大单不足"
 
        return True, ""
 
    @classmethod
    def big_order_deal(cls, code):
        """
        有大单成交
        @param code:
        @param count:
        @return:
        """
        if gpcode_manager.MustBuyCodesManager().is_in_cache(code):
            return
        cls.place_order_success(code)
 
    @classmethod
    def place_order_success(cls, code):
        # 如果有大单成交就加红
        volume_rate = code_volumn_manager.CodeVolumeManager().get_volume_rate(code, with_info=False)
        if volume_rate is None:
            volume_rate = 0.5
        big_order_deal_enough = is_big_order_deal_enough(code,
                                                         volume_rate)  # BigOrderDealManager().get_total_buy_count(code)
        if big_order_deal_enough[0]:
            gpcode_manager.MustBuyCodesManager().add_code(code)
 
 
class ExcludeIndexComputeCodesManager:
    """
    排除身位计算管理器
    """
    __codes_cache = set()
 
    @classmethod
    def add_code(cls, code):
        cls.__codes_cache.add(code)
 
    @classmethod
    def remove_code(cls, code):
        cls.__codes_cache.discard(code)
 
    @classmethod
    def get_all_codes(cls):
        return cls.__codes_cache
 
    @classmethod
    def is_in_cache(cls, code):
        return code in cls.__codes_cache
 
 
class BlockPlaceOrderRecordManager:
    """
    板块下单记录
    """
    __db = 2
    __redis_manager = redis_manager.RedisManager(2)
    __instance = None
    # 下单板块的代码记录
    __block_record_codes_dict = {}
    __codes = set()
 
    def __new__(cls, *args, **kwargs):
        if not cls.__instance:
            cls.__instance = super(BlockPlaceOrderRecordManager, cls).__new__(cls, *args, **kwargs)
            cls.__load_data()
        return cls.__instance
 
    @classmethod
    def __get_redis(cls):
        return cls.__redis_manager.getRedis()
 
    @classmethod
    def __load_data(cls):
        val = RedisUtils.get(cls.__get_redis(), "radical_place_order_block_records")
        if val:
            val = json.loads(val)
            for v in val:
                cls.__block_record_codes_dict[v[0]] = set(v[1])
                cls.__codes |= set(v[1])
 
    def add_record(self, code, blocks):
        """
        添加下单记录
        @param code:
        @param blocks:
        @return:
        """
        if blocks:
            for b in blocks:
                if b not in self.__block_record_codes_dict:
                    self.__block_record_codes_dict[b] = set()
                self.__block_record_codes_dict[b].add(code)
            datas = [(b, list(self.__block_record_codes_dict[b])) for b in self.__block_record_codes_dict]
            RedisUtils.set_async(self.__db, "radical_place_order_block_records", tool.get_expire(), json.dumps(datas))
            self.__codes.add(code)
 
    def get_block_codes(self, block):
        """
        获取板块下过单的代码
        @param block:
        @return:
        """
        if block in self.__block_record_codes_dict:
            return self.__block_record_codes_dict[block]
        return set()
 
    def get_codes(self):
        return self.__codes
 
 
def is_big_order_deal_enough(code, volume_rate):
    """
    大单成交是否足够
    @param code:
    @param volume_rate:
    @return: 大单是否足够, 原因, 是否是短时生效
    """
    limit_up_price = gpcode_manager.get_limit_up_price_as_num(code)
    refer_volume = code_volumn_manager.CodeVolumeManager().get_max_volume_in_5days(code)
    if refer_volume is None:
        refer_volume = 0
 
    money_y = int(refer_volume * limit_up_price / 1e8)
    money_y = min(money_y, 50)
    money_y = max(money_y, 5)
    before_time = tool.get_now_time_as_int() < 93200
    # 计算大单参考数量
    threshold_count = 1  # int(round(0.4 * money_y))
    if before_time:
        threshold_count = int(round(0.4 * money_y * 1.5))
    threshold_money = threshold_count * 299 * 10000
 
    if volume_rate >= 0.5 or True:
        # 按量大于50%算
        # 当换手量>50%时,则,不需要每次扫入时需要≥2笔大单,而是累计需要≥2笔大单即可
        deal_big_order_money = BigOrderDealManager().get_total_buy_money(code)
        try:
            # 获取正在成交的订单
            dealing_order_info = HuaXinBuyOrderManager().get_dealing_order_info(code)
            threshold_big_money = l2_data_util.get_big_money_val(limit_up_price, tool.is_ge_code(code))
            if dealing_order_info and dealing_order_info[2] >= threshold_big_money:
                # 正在成交的订单是大单
                deal_big_order_money += dealing_order_info[2]
        except Exception as e:
            async_log_util.info(logger_l2_radical_buy, f"计算正在成交大单出错:{str(e)}")
 
        if deal_big_order_money >= threshold_money:
            return True, f"量比-{volume_rate}, 总大单成交金额({deal_big_order_money})>={threshold_money}", before_time
        else:
            return False, f"量比-{volume_rate}, 总大单成交金额({deal_big_order_money})<{threshold_money}", before_time
    else:
        current_big_order_deal_count = EveryLimitupBigDealOrderManager.get_big_buy_deal_order_count(code)
        if current_big_order_deal_count >= threshold_count:
            return True, f"量比-{volume_rate}, 本次大单成交数量({current_big_order_deal_count})>={threshold_count}", before_time
        else:
            return False, f"量比-{volume_rate}, 本次大单成交数量({current_big_order_deal_count})<{threshold_count}", before_time
 
 
class EveryLimitupBigDealOrderManager:
    """
    每次上板的大单管理
    """
    # 成交大单的订单号:{"code":{"order_no",...}}
    __deal_big_order_nos_dict = {}
 
    @classmethod
    def open_limit_up(cls, code):
        if code in cls.__deal_big_order_nos_dict:
            cls.__deal_big_order_nos_dict[code].clear()
 
    @classmethod
    def add_big_buy_order_deal(cls, code, order_nos: list):
        if code not in cls.__deal_big_order_nos_dict:
            cls.__deal_big_order_nos_dict[code] = set()
        for order_no in order_nos:
            cls.__deal_big_order_nos_dict[code].add(order_no)
 
    @classmethod
    def get_big_buy_deal_order_count(cls, code):
        if code in cls.__deal_big_order_nos_dict:
            return len(cls.__deal_big_order_nos_dict[code])
        return 0
 
 
def __get_deal_reasons(code):
    """
    获取成交的原因
    @param code:
    @return:
    """
    reasons = set()
    # 当前的涨停原因
    limit_up_reason = kpl_data_manager.LimitUpDataConstant.get_limit_up_reason_with_history(code)
    if limit_up_reason and limit_up_reason in constant.KPL_INVALID_BLOCKS:
        limit_up_reason = None
    # 如果涨停原因为空就需要获取上次激进买的原因
    if limit_up_reason:
        reasons.add(limit_up_reason)
    if not limit_up_reason:
        radical_buy_deal_blocks = RadicalBuyDealCodesManager.radical_buy_blocks_dict.get(code)
        if radical_buy_deal_blocks:
            reasons |= radical_buy_deal_blocks
    return reasons
 
def is_block_can_radical_buy(code, radical_buy_blocks, deal_codes):
    """
    板块是否还能买入
    @param code:
    @param radical_buy_blocks: 板块
    @param deal_codes: 成交的代码
    @return:
    """
    # 原因下面的代码个数
    deal_reason_codes = {}
 
    for dc in deal_codes:
        # 获取涨停原因
        reasons = __get_deal_reasons(dc)
        for r in reasons:
            if r not in deal_reason_codes:
                deal_reason_codes[r] = set()
            deal_reason_codes[r].add(dc)
    async_log_util.info(logger_l2_radical_buy, f"已经成交的板块:{code}-{deal_reason_codes.keys()}")
 
    f_buy_blocks = set()
    for b in radical_buy_blocks:
        # 获取板块的最大买入个数
        max_count = RadicalBuyBlockCodeCountManager().get_block_code_count(b)
        if b in deal_reason_codes and len(deal_reason_codes[b]) >= max_count:
            continue
        f_buy_blocks.add(b)
    async_log_util.info(logger_l2_radical_buy, f"还可以买入的板块:{code}-{f_buy_blocks}")
    return f_buy_blocks
 
 
def get_deal_codes_by_block(block, deal_codes):
    """
    获取板块成交的代码
    @param block:
    @param deal_codes:
    @return:
    """
    codes = set()
    for dc in deal_codes:
        # 获取涨停原因
        reasons = __get_deal_reasons(dc)
        if block in reasons:
            codes.add(block)
    return codes
 
 
def get_volume_rate_threshold(code, volume_rate):
    """
    获取吃卖1的比例
    @param code: 代码
    @param volume_rate:量比
    @return:
    """
    fvolume_rate = volume_rate
    if volume_rate <= 0.05:
        fvolume_rate = 0.05
    elif volume_rate > 1:
        fvolume_rate = 1
 
    if tool.is_sh_code(code):
        return round(0 - 0.44 * fvolume_rate + 0.822, 3)
    else:
        return round(0 - 0.44 * fvolume_rate + 0.722, 3)