From 28e91366d6ae335358239f89819424d4133d79d6 Mon Sep 17 00:00:00 2001 From: yanweidong Date: Sat, 29 Aug 2026 00:44:41 +0800 Subject: [PATCH] dev 6 --- api/QMT_API.py | 47 +++++++++++------- api/__pycache__/QMT_API.cpython-311.pyc | Bin 137287 -> 139044 bytes .../AUDIT_AND_REMEDIATION.md | 0 todo.md => docs/todo.md | 0 py-client/main.py | 5 +- py-client/sdk/trade.py | 2 +- py-client/strategy/ipo/boot.py | 22 ++++++++ .../trend/__pycache__/order.cpython-311.pyc | Bin 11414 -> 11407 bytes .../trend/__pycache__/runtime.cpython-311.pyc | Bin 2191 -> 2189 bytes py-client/strategy/trend/boot.py | 13 ++--- .../__pycache__/test_trend.cpython-311.pyc | Bin 11738 -> 13561 bytes 11 files changed, 61 insertions(+), 28 deletions(-) rename AUDIT_AND_REMEDIATION.md => docs/AUDIT_AND_REMEDIATION.md (100%) rename todo.md => docs/todo.md (100%) create mode 100644 py-client/strategy/ipo/boot.py diff --git a/api/QMT_API.py b/api/QMT_API.py index 79e9d09..17a9cc9 100644 --- a/api/QMT_API.py +++ b/api/QMT_API.py @@ -23,9 +23,14 @@ locale.setlocale(locale.LC_CTYPE, 'chinese') def safe_call(func, *args, **kwargs): try: return func(*args, **kwargs) + except HTTPError: + raise except Exception as e: - logger.error(f"{func.__name__} call failed: {e}") - return None + logger.exception("%s call failed", func.__name__) + raise HTTPError( + 502, + reason="QMT upstream call failed: %s" % func.__name__, + ) from e # ============= BaseHandler ============= @@ -662,23 +667,31 @@ class PassorderHandler(BaseHandler): quickTrade = int(data.get('quickTrade', 2)) strategy_name = str(data.get('strategyName', '')).strip() order_id = str(data.get('orderId', '')).strip() - # QMT stores strategyName in the order remark; preserve the signal key and local order ID. - # Put the local ID first so restart reconciliation still works if QMT truncates the remark. - remark = '|'.join(part for part in (order_id, strategy_name) if part)[:24] + except (json.JSONDecodeError, KeyError, TypeError, ValueError) as e: + raise HTTPError(400, reason="Invalid order parameters: %s" % e) from e + + # QMT stores strategyName in the order remark; preserve the signal key and local order ID. + # Put the local ID first so restart reconciliation still works if QMT truncates the remark. + remark = '|'.join(part for part in (order_id, strategy_name) if part)[:24] + try: order_ref = passorder(opType, orderType, self.acc(), stock, pr_type, price, volume, remark, quickTrade, self.ctx()) - if not order_ref: - raise HTTPError(502, "QMT did not return a valid order reference") - self.write(json.dumps({ - "status": "success", - "opType": opType, - "stock": stock, - "strategy_name": strategy_name, - "local_order_id": order_id, - "order_ref": str(order_ref) - }, ensure_ascii=False)) + except HTTPError: + raise except Exception as e: logger.exception("passorder failed") - raise HTTPError(400, f"Order submission failed: {str(e)}") + raise HTTPError(502, reason="QMT order submission failed") from e + + if not order_ref: + raise HTTPError(502, reason="QMT did not return a valid order reference") + + self.write(json.dumps({ + "status": "success", + "opType": opType, + "stock": stock, + "strategy_name": strategy_name, + "local_order_id": order_id, + "order_ref": str(order_ref) + }, ensure_ascii=False)) # algo_passorder() - Submit an algorithmic order class AlgoPassorderHandler(BaseHandler): @@ -1428,7 +1441,7 @@ def make_app(): (r"/api/trade/debt_contract", DebtContractHandler), (r"/api/trade/assure_contract", AssureContractHandler), (r"/api/trade/enable_short_contract", EnableShortContractHandler), - (r"/api/trade/ipo_data", IpoDataHandler), + (r"/api/trade/ipo_data", IpoDataHandler), (r"/api/trade/new_purchase_limit", NewPurchaseLimitHandler), # Reference functions diff --git a/api/__pycache__/QMT_API.cpython-311.pyc b/api/__pycache__/QMT_API.cpython-311.pyc index 44f772270aa5147e3982fcf07102f21e42c7ebde..f0f94215540f00b6c8c896e0a15128fccc5b6c00 100644 GIT binary patch delta 12389 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 L$?|nLmjwR{4wjkA diff --git a/AUDIT_AND_REMEDIATION.md b/docs/AUDIT_AND_REMEDIATION.md similarity index 100% rename from AUDIT_AND_REMEDIATION.md rename to docs/AUDIT_AND_REMEDIATION.md diff --git a/todo.md b/docs/todo.md similarity index 100% rename from todo.md rename to docs/todo.md diff --git a/py-client/main.py b/py-client/main.py index ddf0dbb..3070605 100644 --- a/py-client/main.py +++ b/py-client/main.py @@ -18,7 +18,7 @@ if PROJECT_ROOT not in sys.path: from sdk import APIError, Client from strategy.trend.boot import StartTrend - +from strategy.ipo import AutoBuyIpo @dataclass(frozen=True, slots=True) class StrategyDefinition: @@ -124,6 +124,9 @@ def main() -> int: configure_logging(config.global_config.qmt_data_dir) wait_for_qmt_api() + # 自动打新 + AutoBuyIpo() + STRATEGIES[config.account_config.strategy].start_strategy() return 0 except (OSError, yaml.YAMLError, ValueError, RuntimeError, KeyError) as exc: diff --git a/py-client/sdk/trade.py b/py-client/sdk/trade.py index e3fb494..335802c 100644 --- a/py-client/sdk/trade.py +++ b/py-client/sdk/trade.py @@ -7,7 +7,7 @@ ORDER_TYPE_VOLUME, PR_TYPE_LATEST, QUICK_TRADE_NOW = 1101, 5, 2 class TradeMixin: account_type: str - def passorder(self, op_type, stock, volume, order_type=0, pr_type=0, price=0, quick_trade=0, strategy_name=""): + def passorder(self, op_type, stock, volume, order_type=0, pr_type=0, price=0.0, quick_trade=0, strategy_name=""): body = {"opType": op_type, "stock": stock, "price": price, "volume": volume} for key, value in (("orderType", order_type), ("prType", pr_type), ("quickTrade", quick_trade), ("strategyName", strategy_name)): if value: body[key] = value diff --git a/py-client/strategy/ipo/boot.py b/py-client/strategy/ipo/boot.py new file mode 100644 index 0000000..04e7f8f --- /dev/null +++ b/py-client/strategy/ipo/boot.py @@ -0,0 +1,22 @@ +from sdk import Client +import config + +def AutoBuyIpo() -> None: + client = Client( + config.global_config.qmt_base_url, + config.global_config.qmt_token, + config.HTTP_TIMEOUT, + ) + + result = client.ipo_data("STOCK") + for stock in result: + ipo_price = result[stock]['issuePrice'] # 发行价 + maxPurchaseNum = result[stock]['maxPurchaseNum'] # 可申购额度 + client.passorder( + op_type=23, + stock=stock, + volume=maxPurchaseNum, + pr_type=11, + price=ipo_price, + strategy_name="新股申购", + ) \ No newline at end of file diff --git a/py-client/strategy/trend/__pycache__/order.cpython-311.pyc b/py-client/strategy/trend/__pycache__/order.cpython-311.pyc index ebcc8ab7cec1e5921053275d293d273004af68a9..e194695edddfefd2cf9c54e9f7e710fb98813030 100644 GIT binary patch delta 313 zcmbOh*&oTfoR^o2fq{X+zHMUGhmE|c%#4bgJDE4Jh@>#3Ft;*Eg5)lWs$#Ax(e--?GW{2$ z?n@R11_n*0TkOTD$wjFp#kV+1@+V*Aa52>U^XFmhR_Vf8A4OSFYudQ z;5VIHensA3gWyGZ<16yU5TOekrjxxnZ!$V>R^^gnVszf@!1I)c(Rs6)q&SPX*#`zD wRtWKtnSo8HCFTPY6RX+g5LqEsM(54xO0KL-FWEM)Q@_f{ROGa|Ra1}|0G$19Pyhe` delta 301 zcmeB=oEFKuoR^o2fq{YHUF*cGhZ}iQnZ?artYXUZi?U-1OB3@-Vv;h`bqjM#Vm22u zZ($8nTnh@FIT_H$n=tNbDgFjGXO=EW={YB diff --git a/py-client/strategy/trend/__pycache__/runtime.cpython-311.pyc b/py-client/strategy/trend/__pycache__/runtime.cpython-311.pyc index 59df6ca57e1752145bc8f547b4884a85f196acb9..e81d92c6a4d5a3d13a67749596fd3f2195b8ae9b 100644 GIT binary patch delta 104 zcmV-u0GI!d5seWIrwt7X00000H-?dF+p!HQ0s$toI0D=PMRIRuX>?z7a$#d@WpX+o z=(nioy{_cHo#m~V=bD7*w5H~Wx8{t28qIMn~3Fzspq|s=AgXinuO+< MpyjZHvsnc+1Hf1|WB>pF diff --git a/py-client/strategy/trend/boot.py b/py-client/strategy/trend/boot.py index 33e2350..feed013 100644 --- a/py-client/strategy/trend/boot.py +++ b/py-client/strategy/trend/boot.py @@ -84,7 +84,10 @@ def StartTrend() -> None: storeState.reconcile(positions, orders, deals) # 获取本策略的信号开仓数据 - signals = init_signals(config.global_config,["morning","tail","arbitrage"]) + signals = init_signals( + config.global_config, + config.account_config.signal_allow, + ) run = Runtime( client=client, global_cfg=config.global_config, @@ -182,11 +185,3 @@ def RunOnce(run: Runtime, signals) -> None: # 8. 持仓计算。当前 Go 版本的 managePositions 为空,保留扩展入口。 manage_positions(run, ticks, positions, market_ok,assets.available) - - -def SignalFilter(signals, allowed_names): - """只保留账户配置明确允许使用的信号。""" - if not allowed_names: - return [] - allowed = set(allowed_names) - return [signal for signal in signals if signal.signal_key in allowed] diff --git a/py-client/tests/__pycache__/test_trend.cpython-311.pyc b/py-client/tests/__pycache__/test_trend.cpython-311.pyc index bb3a3d83a4e17a63b7ad375db19a0cbb8e98360b..b7abf4abbfe69fae65a966550d248ee31d554cf9 100644 GIT binary patch delta 1771 zcma)+UrbY19LIm>a@$MWTcAK`DSre3u|!d!n`3JTDy=fdpCXGg0}XO7vskD(_s%(} zs}Gw&=Ys5*=(0WZ!7vDzs11o(mW7u&lKsi;a+47fUY0D2$+BSP5|%x5`IR6trrUY= za0cOW_t0YonVOmnm!wZ!HfyGb|u%@J`= z6WW6z1NC6&G-3czi0}cxLj$T1yX362oI#28(J-5H1`38yrZ)})z!D!)N_gnM>JV(Lu9hm^DuF05d%6vL39Aa;gRIxi%z0BD0y39KZ~>zNT8(x7)U{ z8`eTj&1U0f=ZRU%qybq(CbylPw508u`gq2_JOC2`g|NdRWZ`kIs_3IE7oh(g@V z0z#euQg+lZXki`3!VE4h;u;$&w&h{Aq(sx8Ay!jP;e zeQ(P29ei{IF^Z@I0Jn*{P;YiUjiB`n10kxY^j*}sr{sYMm4k}h9~qX?*IhEMO%xM$ zXnmwRwN$M3Jf}4y)&H}H_^m5n6M&1bY~7Z$mh0B?6|k8+Oe;LZ8eK)PBbw)k=4wg0 zT69;-vZHKb^!n)Sm#4k6-W7p&WIY1jk@XlccK8o7*vsO=lylBAzfY_8CF^~9y>DJw zXinw_^!&h>Z&Az{Z@tobb7$Olt2HUs>0+HG)-C2aZ!~<=aP!ziQ<9AMf#cLe_t*JBF)TuXhYF)>*?w(|MuU_7(iKUBT z&W~d84`Q)avPUo3e?K=VdUesOiQZ*Vhd*_&c zqcZ=kwxn3Ei}jjVzfuvinLO!+r11z_^BA$Q_Dr?9y86smI-ukNz_@RZ-;(jb!uzv@ z2f4(bE%ZP6_W(fRKv4nb+i+jnSNUid6Gf-=hr)8&XKUWOhE~J0ZhnjH*rz2DkrJfz z22Uvac>5^%kl8CjL}9UtQ4(T*RYZuII8$jRWQ3iodWD>3_o`AP!tU*uAZHWJ)ekvh zX0tCo=NddK@B}*(-_*ni`8;uS*Ix2sm=O00{5!8X Ub=&qw>EPq1AL-3tcXzx02CE**TmS$7 delta 485 zcmZwBJ1m1y6bJBgZoW2JG+xn`1u4nxL)2?vl8_h#jYZ;%S7`IKzBXTW!@!rL|2 zXRc&a%3RLRrE})Im540cIa5D~V}YF%6OFXt@EH>z%k-(ka-$@7)v7D&1b{8L@1g5p zoj$30cLt=PMgc&zG2={(F#$jdHOG0LuDubQq!({SN>o!ka;R<|#hC@h&kO;;tAkU5 z3cf(O#gT7UNjmq%>Qfy5ic0|SY*@KPTiLq8-zxM-OT8#5SR|3_D&+o5BT4G-&1wV P=il(F^hrU`W4HVTzFvB2