def get_ipo_limit(self, stock_code): """ 查询新股申购额度申购上限 :param stock_code: 申购代码 ID :return: """ logger.warning("目前仅在 佣金宝子类 中实现, 其余券商需要补充")
def read_config(self, path): try: self.account_config = file2dict(path) except ValueError: logger.error("配置文件格式有误,请勿使用记事本编辑,推荐 sublime text") for value in self.account_config: if isinstance(value, int): logger.warning("配置文件的值最好使用双引号包裹,使用字符串,否则可能导致不可知问题")
def get_exchangebill(self, start_date, end_date): """ 查询指定日期内的交割单 :param start_date: 20160211 :param end_date: 20160211 :return: """ logger.warning("目前仅在 华泰子类 中实现, 其余券商需要补充")
def _trade(self, security, price=0, amount=0, volume=0, entrust_bs="buy"): """ 调仓 :param security: :param price: :param amount: :param volume: :param entrust_bs: :return: """ stock = self._search_stock_info(security) balance = self.get_balance()[0] if stock is None: raise exceptions.TradeError(u"没有查询要操作的股票信息") if not volume: volume = int(float(price) * amount) # 可能要取整数 if balance["current_balance"] < volume and entrust_bs == "buy": raise exceptions.TradeError(u"没有足够的现金进行操作") if stock["flag"] != 1: raise exceptions.TradeError(u"未上市、停牌、涨跌停、退市的股票无法操作。") if volume == 0: raise exceptions.TradeError(u"操作金额不能为零") # 计算调仓调仓份额 weight = volume / balance["asset_balance"] * 100 weight = round(weight, 2) # 获取原有仓位信息 position_list = self._get_position() # 调整后的持仓 is_have = False for position in position_list: if position["stock_id"] == stock["stock_id"]: is_have = True position["proactive"] = True old_weight = position["weight"] if entrust_bs == "buy": position["weight"] = weight + old_weight else: if weight > old_weight: raise exceptions.TradeError(u"操作数量大于实际可卖出数量") else: position["weight"] = old_weight - weight position["weight"] = round(position["weight"], 2) if not is_have: if entrust_bs == "buy": position_list.append({ "code": stock["code"], "name": stock["name"], "enName": stock["enName"], "hasexist": stock["hasexist"], "flag": stock["flag"], "type": stock["type"], "current": stock["current"], "chg": stock["chg"], "percent": str(stock["percent"]), "stock_id": stock["stock_id"], "ind_id": stock["ind_id"], "ind_name": stock["ind_name"], "ind_color": stock["ind_color"], "textname": stock["name"], "segment_name": stock["ind_name"], "weight": round(weight, 2), "url": "/S/" + stock["code"], "proactive": True, "price": str(stock["current"]), }) else: raise exceptions.TradeError(u"没有持有要卖出的股票") if entrust_bs == "buy": cash = ((balance["current_balance"] - volume) / balance["asset_balance"] * 100) else: cash = ((balance["current_balance"] + volume) / balance["asset_balance"] * 100) cash = round(cash, 2) logger.info("weight:%f, cash:%f", weight, cash) data = { "cash": cash, "holdings": str(json.dumps(position_list)), "cube_symbol": str(self.account_config["portfolio_code"]), "segment": 1, "comment": "", } try: resp = self.s.post(self.config["rebalance_url"], data=data) # pylint: disable=broad-except except Exception as e: logger.warning("调仓失败: %s ", e) return None else: logger.info("调仓 %s%s: %d", entrust_bs, stock["name"], resp.status_code) resp_json = json.loads(resp.text) if "error_description" in resp_json and resp.status_code != 200: logger.error("调仓错误: %s", resp_json["error_description"]) return [{ "error_no": resp_json["error_code"], "error_info": resp_json["error_description"], }] return [{ "entrust_no": resp_json["id"], "init_date": self._time_strftime(resp_json["created_at"]), "batch_no": "委托批号", "report_no": "申报号", "seat_no": "席位编号", "entrust_time": self._time_strftime(resp_json["updated_at"]), "entrust_price": price, "entrust_amount": amount, "stock_code": security, "entrust_bs": "买入", "entrust_type": "雪球虚拟委托", "entrust_status": "-", }]
def adjust_weight(self, stock_code, weight): """ 雪球组合调仓, weight 为调整后的仓位比例 :param stock_code: str 股票代码 :param weight: float 调整之后的持仓百分比, 0 - 100 之间的浮点数 """ stock = self._search_stock_info(stock_code) if stock is None: raise exceptions.TradeError(u"没有查询要操作的股票信息") if stock["flag"] != 1: raise exceptions.TradeError(u"未上市、停牌、涨跌停、退市的股票无法操作。") # 仓位比例向下取两位数 weight = round(weight, 2) # 获取原有仓位信息 position_list = self._get_position() # 调整后的持仓 for position in position_list: if position["stock_id"] == stock["stock_id"]: position["proactive"] = True position["weight"] = weight if weight != 0 and stock["stock_id"] not in [ k["stock_id"] for k in position_list ]: position_list.append({ "code": stock["code"], "name": stock["name"], "enName": stock["enName"], "hasexist": stock["hasexist"], "flag": stock["flag"], "type": stock["type"], "current": stock["current"], "chg": stock["chg"], "percent": str(stock["percent"]), "stock_id": stock["stock_id"], "ind_id": stock["ind_id"], "ind_name": stock["ind_name"], "ind_color": stock["ind_color"], "textname": stock["name"], "segment_name": stock["ind_name"], "weight": weight, "url": "/S/" + stock["code"], "proactive": True, "price": str(stock["current"]), }) remain_weight = 100 - sum(i.get("weight") for i in position_list) cash = round(remain_weight, 2) logger.info("调仓比例:%f, 剩余持仓 :%f", weight, remain_weight) data = { "cash": cash, "holdings": str(json.dumps(position_list)), "cube_symbol": str(self.account_config["portfolio_code"]), "segment": "true", "comment": "", } try: resp = self.s.post(self.config["rebalance_url"], data=data) # pylint: disable=broad-except except Exception as e: logger.warning("调仓失败: %s ", e) return None logger.info("调仓 %s: 持仓比例%d", stock["name"], weight) resp_json = json.loads(resp.text) if "error_description" in resp_json and resp.status_code != 200: logger.error("调仓错误: %s", resp_json["error_description"]) return [{ "error_no": resp_json["error_code"], "error_info": resp_json["error_description"], }] logger.info("调仓成功 %s: 持仓比例%d", stock["name"], weight) return None
def _execute_trade_cmd(self, trade_cmd, users, expire_seconds, entrust_prop, send_interval): """分发交易指令到对应的 user 并执行 :param trade_cmd: :param users: :param expire_seconds: :param entrust_prop: :param send_interval: :return: """ for user in users: # check expire now = datetime.datetime.now() expire = (now - trade_cmd["datetime"]).total_seconds() if expire > expire_seconds: logger.warning( "策略 [%s] 指令(股票: %s 动作: %s 数量: %s 价格: %s)超时,指令产生时间: %s 当前时间: %s, 超过设置的最大过期时间 %s 秒, 被丢弃", trade_cmd["strategy_name"], trade_cmd["stock_code"], trade_cmd["action"], trade_cmd["amount"], trade_cmd["price"], trade_cmd["datetime"], now, expire_seconds, ) break # check price price = trade_cmd["price"] if not self._is_number(price) or price <= 0: logger.warning( "策略 [%s] 指令(股票: %s 动作: %s 数量: %s 价格: %s)超时,指令产生时间: %s 当前时间: %s, 价格无效 , 被丢弃", trade_cmd["strategy_name"], trade_cmd["stock_code"], trade_cmd["action"], trade_cmd["amount"], trade_cmd["price"], trade_cmd["datetime"], now, ) break # check amount if trade_cmd["amount"] <= 0: logger.warning( "策略 [%s] 指令(股票: %s 动作: %s 数量: %s 价格: %s)超时,指令产生时间: %s 当前时间: %s, 买入股数无效 , 被丢弃", trade_cmd["strategy_name"], trade_cmd["stock_code"], trade_cmd["action"], trade_cmd["amount"], trade_cmd["price"], trade_cmd["datetime"], now, ) break actual_price = self._calculate_price_by_slippage( trade_cmd["action"], trade_cmd["price"]) args = { "security": trade_cmd["stock_code"], "price": actual_price, "amount": trade_cmd["amount"], "entrust_prop": entrust_prop, } try: response = getattr(user, trade_cmd["action"])(**args) except exceptions.TradeError as e: trader_name = type(user).__name__ err_msg = "{}: {}".format(type(e).__name__, e.args) logger.error( "%s 执行 策略 [%s] 指令(股票: %s 动作: %s 数量: %s 价格(考虑滑点): %s 指令产生时间: %s) 失败, 错误信息: %s", trader_name, trade_cmd["strategy_name"], trade_cmd["stock_code"], trade_cmd["action"], trade_cmd["amount"], actual_price, trade_cmd["datetime"], err_msg, ) else: logger.info( "策略 [%s] 指令(股票: %s 动作: %s 数量: %s 价格(考虑滑点): %s 指令产生时间: %s) 执行成功, 返回: %s", trade_cmd["strategy_name"], trade_cmd["stock_code"], trade_cmd["action"], trade_cmd["amount"], actual_price, trade_cmd["datetime"], response, )
def get_current_deal(self): """获取当日委托列表""" # return self.do(self.config['current_deal']) logger.warning("目前仅在 佣金宝/银河子类 中实现, 其余券商需要补充")