"""
|
买入策略帮助类
|
"""
|
import time
|
|
from code_attribute import gpcode_manager, code_volumn_manager
|
from l2 import l2_data_util, l2_data_source_util, transaction_progress
|
from l2.l2_data_util import L2DataUtil
|
from l2.l2_transaction_data_manager import HuaXinSellOrderStatisticManager
|
from log_module import async_log_util
|
from log_module.log import logger_l2_error
|
from settings.trade_setting import MarketSituationManager, TradeBlockBuyModeManager
|
from trade import trade_data_manager
|
from utils import tool, buy_condition_util, global_util
|
|
|
def is_has_small_batch_cancel(code, start_index, end_index):
|
"""
|
是否有小群撤单:有连续10笔涨停撤单且连续10笔涨停撤单中小于2笔涨停买单
|
@param code:
|
@param total_datas:
|
@param start_index:
|
@param end_index:
|
@return:
|
"""
|
# 从end_index找到start_index
|
limit_up_price = gpcode_manager.get_limit_up_price_as_num(code)
|
min_num = int(round(5000 / limit_up_price))
|
total_datas = l2_data_util.local_today_datas.get(code)
|
end_time_with_ms = l2_data_util.L2DataUtil.get_time_with_ms(total_datas[end_index]["val"])
|
buy_count = 0
|
cancel_count = 0
|
for i in range(end_index - 1, start_index, -1):
|
data = total_datas[i]
|
val = data["val"]
|
if val["num"] < min_num:
|
continue
|
|
if not l2_data_util.L2DataUtil.is_limit_up_price_buy_cancel(val):
|
if l2_data_util.L2DataUtil.is_limit_up_price_buy(val):
|
if cancel_count > 0:
|
# 当统计到一个涨停买撤的时候才能统计买
|
buy_count += 1
|
if buy_count > 1:
|
break
|
continue
|
# 与当前时间相差3s的结束
|
if tool.trade_time_sub_with_ms(end_time_with_ms, l2_data_util.L2DataUtil.get_time_with_ms(val)) > 6000:
|
break
|
|
cancel_count += 1
|
if cancel_count >= 10:
|
break
|
if cancel_count >= 10 and buy_count < 2:
|
return True
|
return False
|
|
|
def is_cancel_rate_reieved(code, threshhold_rate, start_index, end_index):
|
"""
|
撤单比例是否达到某一个阈值
|
@param code:
|
@param threshhold_rate:
|
@param start_index:
|
@param end_index:
|
@return:
|
"""
|
# 统计总共的涨停买
|
limit_up_price = gpcode_manager.get_limit_up_price_as_num(code)
|
min_num = int(round(5000 / limit_up_price))
|
total_datas = l2_data_util.local_today_datas.get(code)
|
buyno_map = l2_data_util.local_today_buyno_map.get(code)
|
buy_count = 0
|
for i in range(start_index, end_index):
|
data = total_datas[i]
|
val = data["val"]
|
if not l2_data_util.L2DataUtil.is_limit_up_price_buy(val):
|
continue
|
if val["num"] < min_num:
|
continue
|
buy_count += 1
|
# 统计总共的涨停买撤
|
cancel_count = 0
|
for i in range(start_index, end_index):
|
data = total_datas[i]
|
val = data["val"]
|
if not l2_data_util.L2DataUtil.is_limit_up_price_buy_cancel(val):
|
continue
|
if val["num"] < min_num:
|
continue
|
|
buy_index = l2_data_source_util.L2DataSourceUtils.get_buy_index_with_cancel_data_v2(data, buyno_map)
|
if buy_index and start_index <= buy_index:
|
cancel_count += 1
|
if buy_count == 0:
|
return False, "买入数量为0"
|
if round(cancel_count / buy_count, 2) > threshhold_rate:
|
return True, f"买入数量-{buy_count} 撤单数量-{cancel_count}"
|
return False, f"买入数量-{buy_count} 撤单数量-{cancel_count}"
|
|
|
def is_far_away_from_trade_index(code, trade_index, buy1_money):
|
"""
|
是否距离成交进度位太远
|
@param code:
|
@param trade_index:
|
@param buy1_money:
|
@return:
|
"""
|
if buy1_money < 1e7:
|
# 买1大于1千万才能计算
|
return False
|
limit_up_price = gpcode_manager.get_limit_up_price_as_num(code)
|
min_num = int(round(5000 / limit_up_price))
|
threshhold_num = int(round(buy1_money * 0.5 / 100 / limit_up_price))
|
total_datas = l2_data_util.local_today_datas.get(code)
|
end_index = total_datas[-1]["index"]
|
total_num = 0
|
canceled_buyno_map = l2_data_util.local_today_canceled_buyno_map.get(
|
code)
|
for i in range(trade_index, end_index + 1):
|
data = total_datas[i]
|
val = data["val"]
|
if not L2DataUtil.is_limit_up_price_buy(val):
|
continue
|
if val["num"] < min_num:
|
continue
|
left_count = l2_data_source_util.L2DataSourceUtils.get_limit_up_buy_no_canceled_count_v2(
|
code,
|
i,
|
total_datas, canceled_buyno_map)
|
if left_count > 0:
|
total_num += val["num"]
|
if total_num > threshhold_num:
|
return True
|
return False
|
|
|
def is_near_by_trade_index(code, trade_index):
|
"""
|
是否距离成交位近
|
@param code:
|
@param trade_index:
|
@return:
|
"""
|
# 获取今日成交量与参考量
|
# today = get_today_volumn(code)
|
# max60, yesterday = get_histry_volumn(code)
|
try:
|
today_volume = code_volumn_manager.get_today_volumn_cache(code)
|
histry_volumn = code_volumn_manager.get_histry_volumn(code)
|
if not today_volume or not histry_volumn:
|
return False, "尚未获取到量"
|
threshhold_volume = (histry_volumn[0][0] - today_volume) // 3
|
limit_up_price = gpcode_manager.get_limit_up_price_as_num(code)
|
threshhold_volumes = threshhold_volume // 100, int(50000 / limit_up_price), int(200000 / limit_up_price)
|
|
total_data = l2_data_util.local_today_datas.get(code)
|
total_count = 0
|
total_big_count = 0
|
total_num = 0
|
for i in range(trade_index + 1, total_data[-1]["index"] + 1):
|
data = total_data[i]
|
val = data["val"]
|
if not l2_data_util.L2DataUtil.is_limit_up_price_buy(val):
|
continue
|
money = val["num"] * float(val["price"])
|
if money < 5000:
|
continue
|
|
left_count = l2_data_source_util.L2DataSourceUtils.get_limit_up_buy_no_canceled_count_v2(
|
code,
|
i,
|
total_data,
|
l2_data_util.local_today_canceled_buyno_map.get(
|
code))
|
if left_count > 0:
|
total_num += val["num"]
|
total_count += 1
|
if money > 29900:
|
total_big_count += 1
|
if threshhold_volumes[2] < total_num:
|
break
|
if threshhold_volumes[1] <= total_num <= threshhold_volumes[2] and total_num < threshhold_volumes[
|
0] and total_big_count > 0:
|
# 剩余的值在500w-2000w之间才会参与计算
|
return True, ""
|
return False, f"未成交手数-{total_num},阈值-{threshhold_volumes[0]},大单数量-{total_big_count}"
|
except Exception as e:
|
async_log_util.error(logger_l2_error, f"计算是否距离成交进度位置近:{str(e)}")
|
return False, "计算异常"
|
|
|
def is_quantization(code, start_index, end_index):
|
"""
|
是否是量化单
|
@param code:
|
@param satrt_index:
|
@param end_index:
|
@return:(是否是量化, 下次可以下单时间)
|
"""
|
THRESHOLD_BUY_COUNT = 20
|
if end_index - start_index + 1 < THRESHOLD_BUY_COUNT:
|
# 总数小于阈值
|
return False, None
|
total_datas = l2_data_util.local_today_datas.get(code)
|
limit_up_price = gpcode_manager.get_limit_up_price_as_num(code)
|
|
buy_count = 0
|
min_num = int(5000 / limit_up_price)
|
trade_index, is_default = transaction_progress.TradeBuyQueue().get_traded_index(code)
|
if trade_index is None:
|
trade_index = 0
|
# 获取成交进度位
|
for i in range(start_index, end_index + 1):
|
val = total_datas[i]["val"]
|
if not L2DataUtil.is_limit_up_price_buy(val):
|
continue
|
if val["num"] < min_num:
|
continue
|
buy_count += 1
|
if buy_count > THRESHOLD_BUY_COUNT:
|
break
|
if buy_count > THRESHOLD_BUY_COUNT:
|
# 判断是否为量化
|
time_as_ms = tool.trade_time_sub_with_ms(
|
L2DataUtil.get_time_with_ms(total_datas[end_index]["val"]),
|
L2DataUtil.get_time_with_ms(total_datas[start_index]["val"]))
|
if time_as_ms <= 10 if tool.is_sz_code(code) else 100:
|
# 深证10ms内,上证100ms内就判定为量化
|
HuaXinSellOrderStatisticManager.clear_latest_deal_volume(code)
|
next_buy_time = time.time() + buy_condition_util.get_cancel_and_buy_space_time(
|
code) / 1000
|
# 如果是首次下单,增加一次下单次数
|
place_order_count = trade_data_manager.PlaceOrderCountManager().get_place_order_count(code)
|
if place_order_count == 0:
|
trade_data_manager.PlaceOrderCountManager().place_order(code)
|
return True, next_buy_time, f"执行位批次数据量({buy_count})大于{THRESHOLD_BUY_COUNT} {start_index}-{end_index}"
|
return False, None
|
else:
|
return False, None
|
|
|
def is_block_can_buy(code, can_buy_result):
|
"""
|
板块是否可买
|
@param code:
|
@param can_buy_result:
|
@return:
|
"""
|
now_timestamp = int(tool.get_now_time_str().replace(":", ""))
|
# 判断板块
|
# (可以买的板块列表, 是否是独苗, 消息简介,可买的强势主线, 板块关键词)
|
if can_buy_result is None:
|
return False, True, "尚未获取到板块信息"
|
|
# 是否是强势30分钟
|
is_in_strong_time_30 = now_timestamp <= int("100000")
|
|
# 获取市场行情
|
situation = MarketSituationManager().get_situation_cache()
|
zylt_threshold_as_yi = buy_condition_util.get_zyltgb_threshold(situation)
|
zyltgb_as_yi = round(global_util.zyltgb_map.get(code) / 100000000, 2)
|
|
if zyltgb_as_yi < zylt_threshold_as_yi[0]:
|
return False, True, f"{zylt_threshold_as_yi[0]}亿以下的都不买({zyltgb_as_yi})"
|
# 测试时可取消注释
|
# if 1 > 0:
|
# return True, False, "买所有"
|
|
if zyltgb_as_yi >= zylt_threshold_as_yi[1]:
|
return False, True, f"{zylt_threshold_as_yi[1]}亿以上的都不买({zyltgb_as_yi})"
|
|
msg_list = []
|
if is_in_strong_time_30:
|
msg_list.append("强势30分钟")
|
# 独苗
|
if not can_buy_result[0] and can_buy_result[1]:
|
msg_list.append("独苗")
|
return True, False, "强势30分钟,独苗"
|
elif not can_buy_result[0]:
|
return False, True, f"强势30分钟,非独苗不满足身位:{can_buy_result[2]}"
|
else:
|
msg_list.append("非独苗")
|
# 后排,满足自由流通市值需要下单
|
return True, False, can_buy_result[2]
|
else:
|
place_order_count = trade_data_manager.PlaceOrderCountManager().get_place_order_count(code)
|
if place_order_count > 0:
|
return True, False, "之前下过单"
|
if not can_buy_result[0]:
|
# 没有板块
|
if can_buy_result[1]:
|
# 是独苗
|
if not TradeBlockBuyModeManager().can_buy_unique_block():
|
# 不能买独苗
|
return False, True, f"非强势30分钟,独苗,不满足身位:{can_buy_result[2]}"
|
else:
|
# 非独苗,没有可以买入的板块
|
return False, True, f"非强势30分钟,非独苗,不满足身位:{can_buy_result[2]}"
|
return True, False, can_buy_result[2]
|