| | |
| | | 对一系列的代码交易变量,下单,撤单进行管理 |
| | | """ |
| | | # 交易管理器 |
| | | import copy |
| | | import datetime |
| | | import json |
| | | import threading |
| | |
| | | |
| | | from code_attribute import gpcode_manager |
| | | from db import mysql_data_delegate as mysql_data, redis_manager_delegate as redis_manager |
| | | from db.mysql_data_delegate import Mysqldb |
| | | from db.redis_manager_delegate import RedisUtils |
| | | from l2.l2_data_manager import OrderBeginPosInfo, TradePointManager |
| | | from log_module import async_log_util |
| | | from output import kp_client_msg_manager |
| | | from trade import trade_data_manager, l2_trade_util, trade_juejin, trade_huaxin |
| | | from trade import trade_data_manager, l2_trade_util, trade_juejin, trade_huaxin, trade_constant |
| | | |
| | | import time as t |
| | | from l2 import l2_data_manager, l2_data_log |
| | | |
| | | from log_module.log import * |
| | | from trade.buy_money_count_setting import BuyMoneyUtil |
| | | from trade.huaxin.huaxin_trade_record_manager import TradeOrderIdManager |
| | | from trade.order_statistic import DealAndDelegateWithBuyModeDataManager |
| | | from trade.trade_data_manager import AccountMoneyManager, RadicalBuyDealCodesManager |
| | | from utils import import_util, tool, huaxin_util |
| | | |
| | | trade_gui = import_util.import_lib("trade.trade_gui") |
| | |
| | | __db = 2 |
| | | __redis_manager = redis_manager.RedisManager(2) |
| | | |
| | | # 未交易 |
| | | TRADE_STATE_NOT_TRADE = 0 |
| | | # 下单 |
| | | TRADE_STATE_BUY_PLACE_ORDER = 10 |
| | | # 已委托买 |
| | | TRADE_STATE_BUY_DELEGATED = 11 |
| | | # 委托取消进行中 |
| | | TRADE_STATE_BUY_CANCEL_ING = 13 |
| | | # 撤销成功 |
| | | TRADE_STATE_BUY_CANCEL_SUCCESS = 14 |
| | | # 买成功 |
| | | TRADE_STATE_BUY_SUCCESS = 12 |
| | | |
| | | guiTrade = trade_gui.THSGuiTrade() if trade_gui is not None else None |
| | | guiTrade = None # trade_gui.THSGuiTrade() if trade_gui is not None else None |
| | | |
| | | latest_trade_delegate_data = [] |
| | | |
| | |
| | | # 开启购买入口 |
| | | class TradeStateManager: |
| | | __instance = None |
| | | __db = 2 |
| | | redisManager = redis_manager.RedisManager(2) |
| | | |
| | | def __new__(cls, *args, **kwargs): |
| | |
| | | # 开启购买入口 |
| | | def open_buy(self): |
| | | self.__trade_buy_state_cache = True |
| | | RedisUtils.setex_async(self.__get_redis(), "trade_buy_state", tool.get_expire(), 1) |
| | | RedisUtils.setex_async(self.__db, "trade_buy_state", tool.get_expire(), 1) |
| | | |
| | | # 关闭购买入口 |
| | | def close_buy(self): |
| | | self.__trade_buy_state_cache = False |
| | | RedisUtils.setex_async(self.__get_redis(), "trade_buy_state", tool.get_expire(), 0) |
| | | RedisUtils.setex_async(self.__db, "trade_buy_state", tool.get_expire(), 0) |
| | | |
| | | # 是否可以下单 |
| | | @classmethod |
| | |
| | | |
| | | # 交易目标票模式 |
| | | class TradeTargetCodeModeManager: |
| | | # 只买辨识度 |
| | | MODE_ONLY_BUY_SPECIAL_CODES = 2 |
| | | # 只买想买单 |
| | | MODE_ONLY_BUY_WANT_CODES = 1 |
| | | # 买所有 |
| | |
| | | self.__trade_buy_mode_cache = self.get_mode() |
| | | |
| | | def set_mode(self, mode): |
| | | if mode != self.MODE_ONLY_BUY_WANT_CODES and mode != self.MODE_BUY_ALL: |
| | | if mode != self.MODE_ONLY_BUY_WANT_CODES and mode != self.MODE_BUY_ALL and mode != self.MODE_ONLY_BUY_SPECIAL_CODES: |
| | | raise Exception("mode参数值错误") |
| | | self.__trade_buy_mode_cache = mode |
| | | RedisUtils.setex(self.__get_redis(), "trade_buy_mode", tool.get_expire(), mode) |
| | |
| | | return self.__trade_buy_mode_cache |
| | | |
| | | |
| | | # 根据分数禁止买的票管理 |
| | | class ForbiddenBuyCodeByScoreManager: |
| | | # 自动撤卖模式管理 |
| | | class AutoCancelSellModeManager: |
| | | # 撤所有 |
| | | MODE_CANCEL_ALL = 0 |
| | | # 撤机器下单 |
| | | MODE_CANCEL_MECHINE = 1 |
| | | |
| | | __instance = None |
| | | __auto_cancel_sell_mode = MODE_CANCEL_ALL |
| | | |
| | | redisManager = redis_manager.RedisManager(2) |
| | | |
| | | def __new__(cls, *args, **kwargs): |
| | | if not cls.__instance: |
| | | cls.__instance = super(ForbiddenBuyCodeByScoreManager, cls).__new__(cls, *args, **kwargs) |
| | | cls.__instance.__redisManager = redis_manager.RedisManager(2) |
| | | cls.__instance.__key = "forbidden_codes_by_score" |
| | | cls.__instance.__forbidden_codes_by_score_cache = RedisUtils.smembers(cls.__instance.__get_redis(), |
| | | cls.__instance.__key) |
| | | cls.__instance = super(AutoCancelSellModeManager, cls).__new__(cls, *args, **kwargs) |
| | | # 初始化设置 |
| | | # 获取交易窗口的锁 |
| | | cls.__auto_cancel_sell_mode = cls.get_mode() |
| | | return cls.__instance |
| | | |
| | | def __get_redis(self): |
| | | return self.__redisManager.getRedis() |
| | | @classmethod |
| | | def __get_redis(cls): |
| | | return cls.redisManager.getRedis() |
| | | |
| | | def add_code(self, code): |
| | | self.__forbidden_codes_by_score_cache.add(code) |
| | | RedisUtils.sadd(self.__get_redis(), self.__key, code) |
| | | def set_mode(self, mode): |
| | | if mode != self.MODE_CANCEL_ALL and mode != self.MODE_CANCEL_MECHINE: |
| | | raise Exception("mode参数值错误") |
| | | self.__auto_cancel_sell_mode = mode |
| | | RedisUtils.setex(self.__get_redis(), "auto_cancel_sell_mode", tool.get_expire(), mode) |
| | | |
| | | def remove_code(self, code): |
| | | self.__forbidden_codes_by_score_cache.discard(code) |
| | | RedisUtils.srem(self.__get_redis(), self.__key, code) |
| | | # 是否可以下单 |
| | | @classmethod |
| | | def get_mode(cls): |
| | | # 默认设置为可交易 |
| | | val = RedisUtils.get(cls.__get_redis(), "auto_cancel_sell_mode") |
| | | if val is None: |
| | | return cls.MODE_CANCEL_ALL |
| | | return int(val) |
| | | |
| | | def is_in(self, code): |
| | | return RedisUtils.sismember(self.__get_redis(), self.__key, code) |
| | | |
| | | def is_in_cache(self, code): |
| | | return code in self.__forbidden_codes_by_score_cache |
| | | |
| | | def clear(self): |
| | | self.__forbidden_codes_by_score_cache.clear() |
| | | RedisUtils.delete(self.__get_redis(), self.__key) |
| | | def get_mode_cache(self): |
| | | return self.__auto_cancel_sell_mode |
| | | |
| | | |
| | | # 代码的交易状态管理 |
| | |
| | | def get_trade_state(self, code): |
| | | state = RedisUtils.get(self.__get_redis(), "trade-state-{}".format(code)) |
| | | if state is None: |
| | | return TRADE_STATE_NOT_TRADE |
| | | return trade_constant.TRADE_STATE_NOT_TRADE |
| | | return int(state) |
| | | |
| | | def get_trade_state_cache(self, code): |
| | | cache_result = tool.CodeDataCacheUtil.get_cache(self.__trade_state_cache, code) |
| | | if cache_result[0]: |
| | | return cache_result[1] |
| | | return TRADE_STATE_NOT_TRADE |
| | | return trade_constant.TRADE_STATE_NOT_TRADE |
| | | |
| | | def get_trade_state_dict(self): |
| | | return copy.deepcopy(self.__trade_state_cache) |
| | | |
| | | # 设置交易状态 |
| | | def set_trade_state(self, code, state): |
| | |
| | | return codes |
| | | |
| | | # 设置交易账户的可用金额 |
| | | |
| | | |
| | | # 账户可用资金管理 |
| | | class AccountAvailableMoneyManager: |
| | | __db = 2 |
| | | __redis_manager = redis_manager.RedisManager(2) |
| | | __available_money_cache = None |
| | | __instance = None |
| | | |
| | | def __new__(cls, *args, **kwargs): |
| | | if not cls.__instance: |
| | | cls.__instance = super(AccountAvailableMoneyManager, cls).__new__(cls, *args, **kwargs) |
| | | __redis = cls.__get_redis() |
| | | result = RedisUtils.get(cls.__get_redis(), "trade-account-canuse-money") |
| | | if result: |
| | | cls.__available_money_cache = round(float(result), 2) |
| | | return cls.__instance |
| | | |
| | | @classmethod |
| | | def __get_redis(cls): |
| | | return cls.__redis_manager.getRedis() |
| | | |
| | | def set_available_money(self, client_id, money): |
| | | self.__available_money_cache = round(float(money), 2) |
| | | RedisUtils.set(self.__get_redis(), "trade-account-canuse-money", money) |
| | | |
| | | # 获取交易账户的可用金额 |
| | | def get_available_money(self): |
| | | result = RedisUtils.get(self.__get_redis(), "trade-account-canuse-money") |
| | | if result is None: |
| | | return None |
| | | return round(float(result), 2) |
| | | |
| | | def get_available_money_cache(self): |
| | | return self.__available_money_cache |
| | | |
| | | |
| | | # 保存交易成功的数据 |
| | |
| | | |
| | | |
| | | # 开始交易 |
| | | def start_buy(code, capture_timestamp, last_data, last_data_index): |
| | | def start_buy(code, capture_timestamp, last_data, last_data_index, mode=0, exec_index=None): |
| | | def is_forbidden(code): |
| | | if l2_trade_util.is_in_forbidden_trade_codes(code): |
| | | return Exception("禁止交易") |
| | |
| | | |
| | | def is_state_right(code): |
| | | trade_state = __CodesTradeStateManager.get_trade_state_cache(code) |
| | | if trade_state != TRADE_STATE_NOT_TRADE and trade_state != TRADE_STATE_BUY_CANCEL_SUCCESS and trade_state != TRADE_STATE_BUY_CANCEL_ING: |
| | | if trade_state != trade_constant.TRADE_STATE_NOT_TRADE and trade_state != trade_constant.TRADE_STATE_BUY_CANCEL_SUCCESS and trade_state != trade_constant.TRADE_STATE_BUY_CANCEL_ING: |
| | | return Exception("代码处于不可交易状态"), trade_state |
| | | return None, trade_state |
| | | |
| | | def is_money_enough(code): |
| | | money = AccountAvailableMoneyManager().get_available_money_cache() |
| | | money = AccountMoneyManager().get_available_money_cache() |
| | | if money is None: |
| | | return Exception("未获取到账户可用资金"), None |
| | | price = gpcode_manager.get_limit_up_price(code) |
| | |
| | | raise ex |
| | | finally: |
| | | async_log_util.info(logger_trade, "{} trade.manager.start_buy 判断是否可买".format(code)) |
| | | __CodesTradeStateManager.set_trade_state(code, TRADE_STATE_BUY_PLACE_ORDER) |
| | | __CodesTradeStateManager.set_trade_state(code, trade_constant.TRADE_STATE_BUY_PLACE_ORDER) |
| | | # 状态改变过后必须要有本地下单编号 |
| | | __buy(code, price, trade_state, capture_timestamp, last_data, last_data_index) |
| | | __buy(code, price, trade_state, capture_timestamp, last_data, last_data_index, mode, exec_index=exec_index) |
| | | finally: |
| | | async_log_util.info(logger_trade, "{} trade.manager.start_buy 结束".format(code)) |
| | | |
| | | |
| | | def test_order(code, last_data, exec_index): |
| | | """ |
| | | TODO 测试下单 |
| | | @param code: |
| | | @param last_data: |
| | | @param exec_index: |
| | | @return: |
| | | """ |
| | | price = gpcode_manager.get_limit_up_price(code) |
| | | __buy(code, price, trade_constant.TRADE_STATE_NOT_TRADE, 0, last_data, last_data["index"], 0, exec_index=exec_index) |
| | | |
| | | |
| | | # 中断买入 |
| | |
| | | |
| | | # 购买 |
| | | # @tool.async_call |
| | | def __buy(code, price, trade_state, capture_timestamp, last_data, last_data_index): |
| | | def __buy(code, price, trade_state, capture_timestamp, last_data, last_data_index, mode=0, exec_index=None): |
| | | async_log_util.info(logger_trade, "{} trade_manager.__buy 开始".format(code)) |
| | | try: |
| | | |
| | | if constant.API_TRADE_ENABLE: |
| | | count = (constant.BUY_MONEY_PER_CODE // int(round(float(price) * 100))) * 100 |
| | | # 最低下单1手 |
| | | if count < 100: |
| | | count = 100 |
| | | can_buy, money, msg = BuyMoneyUtil.get_buy_data(tool.get_now_time_str(), mode, |
| | | DealAndDelegateWithBuyModeDataManager().get_deal_codes_info( |
| | | mode), |
| | | DealAndDelegateWithBuyModeDataManager().get_delegates_codes_info( |
| | | mode)) |
| | | if not can_buy: |
| | | raise Exception(msg) |
| | | count = tool.get_buy_volume_by_money(price, money) |
| | | |
| | | # if mode == OrderBeginPosInfo.MODE_RADICAL: |
| | | # # 激进买入金额为1手 |
| | | # count = 100 |
| | | if constant.TRADE_WAY == constant.TRADE_WAY_JUEJIN: |
| | | trade_juejin.order_volume(code, price, count) |
| | | elif constant.TRADE_WAY == constant.TRADE_WAY_HUAXIN: |
| | | order_ref = huaxin_util.create_order_ref() |
| | | TradeOrderIdManager().add_order_ref(code, order_ref) |
| | | trade_huaxin.order_volume(code, price, count, last_data_index, order_ref=order_ref) |
| | | if constant.IS_NEW_VERSION_PLACE_ORDER: |
| | | trade_huaxin.order_volume_new(code, price, count, last_data, exec_index=exec_index) |
| | | else: |
| | | order_ref = huaxin_util.create_order_ref() |
| | | TradeOrderIdManager().add_order_ref(code, order_ref) |
| | | trade_huaxin.order_volume(code, price, count, last_data, order_ref=order_ref, exec_index=exec_index) |
| | | else: |
| | | guiTrade.buy(code, price) |
| | | __place_order_success(code, capture_timestamp, last_data, last_data_index) |
| | |
| | | |
| | | # 开始取消买入 |
| | | def start_cancel_buy(code, force=False): |
| | | """ |
| | | 开始撤单 |
| | | @param code: |
| | | @param force: |
| | | @return: |
| | | """ |
| | | async_log_util.info(logger_trade, "{} trade_manager.start_cancel_buy 开始".format(code)) |
| | | trade_state = __CodesTradeStateManager.get_trade_state_cache(code) |
| | | try: |
| | | if trade_state == TRADE_STATE_BUY_SUCCESS: |
| | | if trade_state == trade_constant.TRADE_STATE_BUY_SUCCESS: |
| | | return None |
| | | if not force: |
| | | if trade_state != TRADE_STATE_BUY_PLACE_ORDER and trade_state != TRADE_STATE_BUY_DELEGATED: |
| | | if trade_state != trade_constant.TRADE_STATE_BUY_PLACE_ORDER and trade_state != trade_constant.TRADE_STATE_BUY_DELEGATED: |
| | | return None |
| | | __CodesTradeStateManager.set_trade_state(code, TRADE_STATE_BUY_CANCEL_ING) |
| | | __CodesTradeStateManager.set_trade_state(code, trade_constant.TRADE_STATE_BUY_CANCEL_ING) |
| | | if constant.API_TRADE_ENABLE: |
| | | if constant.TRADE_WAY == constant.TRADE_WAY_JUEJIN: |
| | | trade_juejin.cancel_order(code) |
| | |
| | | for i in range(0, 5): |
| | | # 如果时 |
| | | trade_state = CodesTradeStateManager().get_trade_state_cache(code) |
| | | if trade_state != TRADE_STATE_BUY_CANCEL_ING and trade_state != TRADE_STATE_BUY_CANCEL_SUCCESS: |
| | | if trade_state != trade_constant.TRADE_STATE_BUY_CANCEL_ING and trade_state != trade_constant.TRADE_STATE_BUY_CANCEL_SUCCESS: |
| | | return |
| | | try: |
| | | logger_trade.info("{}:开始再次撤单", code) |
| | |
| | | continue |
| | | # 买入成功 |
| | | if code is not None and int(data["type"]) == 0: |
| | | l2_trade_util.forbidden_trade(code, msg="交易成功") |
| | | l2_trade_util.forbidden_trade(code, msg="交易成功", force=True) |
| | | state = CodesTradeStateManager().get_trade_state_cache(code) |
| | | if state != TRADE_STATE_BUY_SUCCESS: |
| | | CodesTradeStateManager().set_trade_state(code, TRADE_STATE_BUY_SUCCESS) |
| | | if state != trade_constant.TRADE_STATE_BUY_SUCCESS: |
| | | CodesTradeStateManager().set_trade_state(code, trade_constant.TRADE_STATE_BUY_SUCCESS) |
| | | # 删除买撤记录的临时信息 |
| | | kp_client_msg_manager.add_msg(code, "买入成交") |
| | | l2_data_manager.TradePointManager().delete_buy_cancel_point(code) |
| | | l2_data_manager.TradePointManager().delete_buy_point(code) |
| | | # 移除交易窗口分配 |
| | | if trade_gui is not None: |
| | | trade_gui.THSBuyWinManagerNew.cancel_distribute_win_for_code(code) |
| | | # 交易成功时间过去3s之后,且当前委托列表里面还有该代码数据就再次执行撤单 |
| | | if tool.trade_time_sub(tool.get_now_time_str(), _time) > 3: |
| | | # 获取到当前是否委托 |
| | | for dd in latest_trade_delegate_data: |
| | | if dd["code"] == code: |
| | | logger_trade.info("{}交易成功触发,重复下单撤单".format(code)) |
| | | start_cancel_buy(code, True) |
| | | # 新版下单不处理 |
| | | if not constant.IS_NEW_VERSION_PLACE_ORDER: |
| | | if tool.trade_time_sub(tool.get_now_time_str(), _time) > 3: |
| | | # 获取到当前是否委托 |
| | | for dd in latest_trade_delegate_data: |
| | | if dd["code"] == code: |
| | | logger_trade.info("{}交易成功触发,重复下单撤单".format(code)) |
| | | start_cancel_buy(code, True) |
| | | |
| | | |
| | | # 处理委托成功数据 |
| | |
| | | latest_trade_delegate_data.extend(datas) |
| | | codes = [] |
| | | for data in datas: |
| | | |
| | | code = data["code"] |
| | | if code is not None: |
| | | codes.append(code) |
| | | trade_state = CodesTradeStateManager().get_trade_state_cache(code) |
| | | # 设置下单状态的代码为已委托 |
| | | if trade_state == TRADE_STATE_BUY_PLACE_ORDER: |
| | | CodesTradeStateManager().set_trade_state(code, TRADE_STATE_BUY_DELEGATED) |
| | | if trade_state == trade_constant.TRADE_STATE_BUY_PLACE_ORDER: |
| | | CodesTradeStateManager().set_trade_state(code, trade_constant.TRADE_STATE_BUY_DELEGATED) |
| | | if constant.TRADE_WAY == constant.TRADE_WAY_JUEJIN: |
| | | ing_codes = CodesTradeStateManager().get_codes_by_trade_state(TRADE_STATE_BUY_CANCEL_ING) |
| | | ing_codes = CodesTradeStateManager().get_codes_by_trade_state(trade_constant.TRADE_STATE_BUY_CANCEL_ING) |
| | | if ing_codes is not None: |
| | | for code in ing_codes: |
| | | if code in codes: |
| | | # 强制重新取消 |
| | | start_cancel_buy(code, True) |
| | | else: |
| | | CodesTradeStateManager().set_trade_state(code, TRADE_STATE_BUY_CANCEL_SUCCESS) |
| | | CodesTradeStateManager().set_trade_state(code, trade_constant.TRADE_STATE_BUY_CANCEL_SUCCESS) |
| | | l2_data_manager.remove_from_l2_fixed_codes(code) |
| | | |
| | | |
| | |
| | | RedisUtils.realse(redis_l2) |
| | | |
| | | |
| | | # 买入成功 |
| | | def buy_success(code): |
| | | # 加入黑名单 |
| | | if not l2_trade_util.is_in_forbidden_trade_codes(code): |
| | | l2_trade_util.forbidden_trade(code, "buy success", force=True) |
| | | mode = TradePointManager().get_latest_place_order_mode(code) |
| | | if mode is None: |
| | | mode = OrderBeginPosInfo.MODE_NORMAL |
| | | DealAndDelegateWithBuyModeDataManager().add_deal_code(code, tool.get_now_time_str(), mode) |
| | | if mode == OrderBeginPosInfo.MODE_RADICAL: |
| | | RadicalBuyDealCodesManager().add_deal_code(code) |
| | | # 取s消所有的挂单 |
| | | if constant.API_TRADE_ENABLE: |
| | | if not constant.IS_NEW_VERSION_PLACE_ORDER: |
| | | # 新版本拆单下单不撤单 |
| | | if constant.TRADE_WAY == constant.TRADE_WAY_JUEJIN: |
| | | trade_juejin.cancel_order(code) |
| | | elif constant.TRADE_WAY == constant.TRADE_WAY_HUAXIN: |
| | | trade_huaxin.cancel_order(code) |
| | | else: |
| | | guiTrade.cancel_buy(code) |
| | | |
| | | |
| | | if __name__ == "__main__": |
| | | print(CodesTradeStateManager().get_codes_by_trade_states_cache([0, 1])) |
| | | print(CodesTradeStateManager().get_trade_state_cache("002235")) |