def cancel_entrust(self, entrust_no): """ 对未成交的调仓进行伪撤单 :param entrust_no: :return: """ xq_entrust_list = self._get_xq_history() is_have = False for xq_entrusts in xq_entrust_list: status = xq_entrusts["status"] # 调仓状态 for entrust in xq_entrusts["rebalancing_histories"]: if entrust["id"] == entrust_no and status == "pending": is_have = True buy_or_sell = ("buy" if entrust["target_weight"] < entrust["weight"] else "sell") if (entrust["target_weight"] == 0 and entrust["weight"] == 0): raise exceptions.TradeError(u"移除的股票操作无法撤销,建议重新买入") balance = self.get_balance()[0] volume = ( abs(entrust["target_weight"] - entrust["weight"]) * balance["asset_balance"] / 100) r = self._trade( security=entrust["stock_symbol"], volume=volume, entrust_bs=buy_or_sell, ) if len(r) > 0 and "error_info" in r[0]: raise exceptions.TradeError(u"撤销失败!%s" % ("error_info" in r[0])) if not is_have: raise exceptions.TradeError(u"撤销对象已失效") return True
def handle(self, title) -> Optional[dict]: if title == "委托确认": self._submit_by_shortcut() return None if title == "提示信息": content = self._extract_content() if "超出涨跌停" in content: self._submit_by_shortcut() return None if "委托价格的小数价格应为" in content: self._submit_by_shortcut() return None if "逆回购" in content: self._submit_by_shortcut() return None return None if title == "提示": content = self._extract_content() if "成功" in content: entrust_no = self._extract_entrust_id(content) self._submit_by_click() return {"entrust_no": entrust_no} self._submit_by_click() time.sleep(0.05) raise exceptions.TradeError(content) # self._close() #不关闭程序 edited by leonardo return None
def detect_yh_client_result(image_path): """封装了tesseract的识别,部署在阿里云上, 服务端源码地址为: https://github.com/shidenggui/yh_verify_code_docker""" api = "http://yh.ez.shidenggui.com:5000/yh_client" with open(image_path, "rb") as f: rep = requests.post(api, files={"image": f}) if rep.status_code != 201: error = rep.json()["message"] raise exceptions.TradeError("request {} error: {}".format(api, error)) return rep.json()["result"]
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