@vibek/strategy 0.6.9 → 0.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +2 -2
  2. package/package.json +1 -1
  3. package/testing.js +32 -10
package/README.md CHANGED
@@ -5,10 +5,10 @@ Vibek 的公开 Strategy SDK 与 Bun Testing helper。
5
5
  ## 安装
6
6
 
7
7
  ```bash
8
- bun add @vibek/strategy@0.6.9
8
+ bun add @vibek/strategy@0.7.1
9
9
  ```
10
10
 
11
- 当前包版本为 `0.6.9`;对应 CLI 应为 `@vibek/cli@0.6.9`。
11
+ 当前包版本为 `0.7.1`;对应 CLI 应为 `@vibek/cli@0.7.1`。
12
12
 
13
13
  ## 使用
14
14
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vibek/strategy",
3
- "version": "0.6.9",
3
+ "version": "0.7.1",
4
4
  "description": "Public Vibek strategy SDK and Bun testing helper",
5
5
  "license": "MIT",
6
6
  "type": "module",
package/testing.js CHANGED
@@ -1,7 +1,7 @@
1
1
  // @bun
2
- var wt=import.meta.require;function w(e){return e.status==="submitting"||e.status==="notTraded"||e.status==="partTraded"}var br=Symbol.for("vibek.strategy.cta-template-runtime");function St(e){if(!e||typeof e!=="object")return null;let t=e[br];if(typeof t!=="function")return null;let r=t.call(e);if(!r||typeof r.bindContext!=="function"||typeof r.restoreVariables!=="function"||typeof r.setRuntimeState!=="function"||typeof r.getStateVariables!=="function")return null;return r}var we=/^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$/;var kr=["strategyName","vtSymbol","mode","inited","trading","pos"],Xn=new Set([...kr,"constructor","__proto__","prototype","onInit","onStart","onStop","onTick","onBar","onTrade","onOrder","buy","sell","short","cover","cancelOrder","cancelAll","loadBars","registerEvent","claimOrder","writeLog","emitHook","getCurrentTime","getContract","getCommission","getPriceTick","getSize"]);function Se(e,t,r){if(!Sr(e))throw Error("\u7B56\u7565 default export \u5FC5\u987B\u662F\u5BF9\u8C61");let n=Object.keys(e).find((p)=>p!=="strategy");if(n)throw Error(`\u7B56\u7565\u5B9A\u4E49\u4E0D\u652F\u6301\u5B57\u6BB5 "${n}"\uFF1Bid\u3001vtSymbol \u548C setting \u5FC5\u987B\u5728\u52A0\u8F7D\u65F6\u4F20\u5165`);if(typeof e.strategy!=="function")throw Error(`\u7B56\u7565 ${t} \u7684 strategy \u5FC5\u987B\u662F\u7C7B`);if(!Sr(r))throw Error(`\u7B56\u7565 ${t} \u7684 setting \u5FC5\u987B\u662F\u5BF9\u8C61`);let i=e.strategy,o=wr(i.parameters,"parameters",t),s=wr(i.variables,"variables",t),a=[...o,...s].find((p)=>Xn.has(p));if(a)throw Error(`\u7B56\u7565 ${t} \u7684 parameters/variables \u4E0D\u5E94\u58F0\u660E\u6846\u67B6\u5B57\u6BB5 ${a}`);let d=o.find((p)=>s.includes(p));if(d)throw Error(`\u7B56\u7565 ${t} \u7684\u5B57\u6BB5 ${d} \u4E0D\u80FD\u540C\u65F6\u5C5E\u4E8E parameters \u548C variables`);let c=Object.keys(r).find((p)=>!o.includes(p));if(c)throw Error(`\u7B56\u7565 ${t} \u4E0D\u652F\u6301\u53C2\u6570 "${c}"`);let u;try{u=new i}catch(p){throw Error(`\u7B56\u7565 ${t} \u6784\u9020\u5931\u8D25: ${p instanceof Error?p.message:String(p)}`)}let l=St(u);if(!l||typeof u.onInit!=="function")throw Error(`\u7B56\u7565 ${t} \u5FC5\u987B\u7EE7\u627F CtaTemplate \u5E76\u5B9E\u73B0 onInit()`);for(let p of kr)if(Object.hasOwn(u,p))throw Error(`\u7B56\u7565 ${t} \u4E0D\u5F97\u58F0\u660E\u6846\u67B6\u5B57\u6BB5 ${p}`);for(let p of[...o,...s])if(!(p in u))throw Error(`\u7B56\u7565 ${t} \u58F0\u660E\u4E86\u5B57\u6BB5 ${p}\uFF0C\u4F46\u5B9E\u4F8B\u6CA1\u6709\u5BF9\u5E94\u9ED8\u8BA4\u503C`);let f=o.map((p)=>{let k=Tr(ti(u,p),`\u7B56\u7565 ${t} \u53C2\u6570 ${p} \u9ED8\u8BA4\u503C`);return{name:p,defaultValue:k,kind:ei(k)}}),h=vr(r,`\u7B56\u7565 ${t} setting`),m=Object.fromEntries(f.map((p)=>[p.name,Object.hasOwn(h,p.name)?h[p.name]:p.defaultValue]));return{definition:{strategy:i},ctor:i,instance:u,runtime:l,effectiveSetting:vr(m,`\u7B56\u7565 ${t} \u751F\u6548 setting`),inspection:{name:i.name,author:i.author??"",parameters:f}}}function wr(e,t,r){if(e===void 0)return[];if(!Array.isArray(e))throw Error(`\u7B56\u7565 ${r} \u7684 ${t} \u5FC5\u987B\u662F\u5B57\u7B26\u4E32\u6570\u7EC4`);let n=e.map((i,o)=>{if(typeof i!=="string"||!/^[A-Za-z_$][A-Za-z0-9_$]*$/.test(i))throw Error(`\u7B56\u7565 ${r} \u7684 ${t}[${o}] \u975E\u6CD5`);return i});if(new Set(n).size!==n.length)throw Error(`\u7B56\u7565 ${r} \u7684 ${t} \u5B58\u5728\u91CD\u590D\u9879`);return n}function ei(e){if(typeof e==="number")return"number";if(typeof e==="boolean")return"boolean";if(typeof e==="string")return"string";return"json"}function ti(e,t){return e[t]}function Sr(e){return e!==null&&typeof e==="object"&&!Array.isArray(e)}function vr(e,t){return Tr(e,t)}function Tr(e,t){return vt(e,t,new Set),JSON.parse(JSON.stringify(e))}function vt(e,t,r){if(e===null||typeof e==="string"||typeof e==="boolean")return;if(typeof e==="number"){if(!Number.isFinite(e))throw Error(`${t} \u5305\u542B\u975E\u6709\u9650\u6570\u5B57`);return}if(typeof e!=="object")throw Error(`${t} \u5305\u542B\u4E0D\u53EF\u5E8F\u5217\u5316\u7684 ${typeof e}`);if(r.has(e))throw Error(`${t} \u5305\u542B\u5FAA\u73AF\u5F15\u7528`);if(r.add(e),Array.isArray(e))for(let n=0;n<e.length;n++)vt(e[n],`${t}[${n}]`,r);else{let n=Object.getPrototypeOf(e);if(n!==Object.prototype&&n!==null)throw Error(`${t} \u5FC5\u987B\u662F\u666E\u901A\u5BF9\u8C61\u6216\u6570\u7EC4`);for(let[i,o]of Object.entries(e))vt(o,`${t}.${i}`,r)}r.delete(e)}class qe{timeframes;currentBars=new Map;completedBars=[];tickCallbacks=[];barCallbacks=[];lastTickTime=0;lastCumVolume=null;lastTradingDay="";constructor(e){this.timeframes=e.timeframes.map((t)=>({label:t,seconds:Ir(t)}))}onTick(e){this.tickCallbacks.push(e)}offTick(e){let t=this.tickCallbacks.indexOf(e);if(t>=0)this.tickCallbacks.splice(t,1)}onBar(e){this.barCallbacks.push(e)}offBar(e){let t=this.barCallbacks.indexOf(e);if(t>=0)this.barCallbacks.splice(t,1)}pushTick(e){let t=ni(e);if(this.lastTickTime>0&&t<this.lastTickTime)throw Error(`tick \u65F6\u95F4\u56DE\u9000: ${e.code} ${t} < ${this.lastTickTime}`);this.lastTickTime=t;let r=Boolean(e.tradingDay&&this.lastTradingDay&&e.tradingDay!==this.lastTradingDay),n=0;if(!r&&this.lastCumVolume!==null&&e.volume>=this.lastCumVolume)n=e.volume-this.lastCumVolume;if(this.lastCumVolume=e.volume,e.tradingDay)this.lastTradingDay=e.tradingDay;for(let i of this.tickCallbacks)i(e);for(let i of this.timeframes)this.updateBar(i,e,t,n)}completeThrough(e){let t=Math.floor(e/1000);for(let r of this.timeframes){let n=this.currentBars.get(r.label);if(n&&n.barTime+r.seconds<=t)this.finalizeBar(r.label)}}getCompletedBars(){return this.completedBars}getCurrentBar(e){return this.currentBars.get(e)??null}forceCompleteAll(e){for(let t of this.timeframes)this.finalizeBar(t.label,e)}forceComplete(e,t){if(this.timeframes.some((r)=>r.label===e))this.finalizeBar(e,t)}markDisconnected(){for(let e of this.currentBars.values())e.boundaryReason="disconnect";this.lastCumVolume=null}reset(){this.currentBars.clear(),this.completedBars=[],this.lastTickTime=0,this.lastCumVolume=null,this.lastTradingDay=""}clearCompletedBars(){this.completedBars=[]}_registrySize(){return this.currentBars.size}updateBar(e,t,r,n){let i=ri(r,e.seconds),o=t.lastPrice,s=this.currentBars.get(e.label);if(s&&s.barTime<i)this.finalizeBar(e.label),s=void 0;if(!s){this.currentBars.set(e.label,{code:t.code,timeframe:e.label,barTime:i,open:o,high:o,low:o,close:o,volume:n,tickCount:1,...t.tradingDay?{tradingDay:t.tradingDay}:{}});return}if(s.high=Math.max(s.high,o),s.low=Math.min(s.low,o),s.close=o,s.volume+=n,s.tickCount++,t.tradingDay)s.tradingDay=t.tradingDay}finalizeBar(e,t){let r=this.currentBars.get(e);if(!r)return;if(this.currentBars.delete(e),r.tickCount===0)return;let n=t??r.boundaryReason,i={code:r.code,timeframe:r.timeframe,barTime:r.barTime,open:r.open,high:r.high,low:r.low,close:r.close,volume:r.volume,...r.tradingDay?{tradingDay:r.tradingDay}:{},...n?{boundaryReason:n}:{}};if(this.completedBars.push(i),this.completedBars.length>1000)this.completedBars.shift();for(let o of this.barCallbacks)o(i)}}function Ir(e){let t=/^(\d+)(min|h|d)$/.exec(e);if(!t)throw Error(`\u4E0D\u652F\u6301\u7684 K \u7EBF\u5468\u671F: ${e}`);let r=Number(t[1]);if(!Number.isInteger(r)||r<=0)throw Error(`\u4E0D\u652F\u6301\u7684 K \u7EBF\u5468\u671F: ${e}`);if(t[2]==="min")return r*60;if(t[2]==="h")return r*3600;return r*86400}function ri(e,t){return Math.floor(e/t)*t}function ni(e){if(Number.isFinite(e.datetime))return Math.floor(e.datetime/1000);return Math.floor(Or(e.actionDay,e.updateTime,e.updateMillisec??0)/1000)}var Dr=28800000,kt=86400000;function ii(e){let r=((e+Dr)%kt+kt)%kt;return e-r}function oi(e){if(!e||!/^\d{8}$/.test(e))return null;let t=Number(e.slice(0,4)),r=Number(e.slice(4,6)),n=Number(e.slice(6,8)),i=new Date(Date.UTC(t,r-1,n));return i.getUTCFullYear()===t&&i.getUTCMonth()===r-1&&i.getUTCDate()===n?[t,r,n]:null}var Er=new Set,si=43200000;function Or(e,t,r){if(!t)return Date.now();let n=/^(\d{2}):(\d{2}):(\d{2})$/.exec(t);if(!n){let d=new Date(t).getTime();return Number.isNaN(d)?Date.now():d}let i=Number(n[1]),o=Number(n[2]),s=Number(n[3]);if(i>23||o>59||s>59||!Number.isInteger(r)||r<0||r>999)return Date.now();let a=oi(e);if(a){let d=Date.UTC(a[0],a[1]-1,a[2],i,o,s,r)-Dr,c=Math.abs(d-Date.now());if(c>si&&!Er.has(e))Er.add(e),console.warn(`[bar-aggregator] actionDay \u4E0E\u7CFB\u7EDF\u65E5\u671F\u504F\u5DEE ${Math.round(c/3600000)}h: ${e}`);return d}return ii(Date.now())+(i*3600+o*60+s)*1000+r}var Ve=["1min","3min","5min","10min","15min","30min","1h","2h","4h","1d"],se={"1min":60,"3min":180,"5min":300,"10min":600,"15min":900,"30min":1800,"1h":3600,"2h":7200,"4h":14400,"1d":86400};var ve=Ve.join("\u3001");var ai=/^(\d{4})(\d{2})(\d{2})$/;function Z(e){return typeof e==="string"&&Ve.includes(e)}function ze(e,t,r){if(t!=="1d"){let n=se[t];return Math.floor(e/n)*n}return di(r??Tt(e))}function Tt(e){let t=new Date((e+28800)*1000);if(t.getUTCHours()>=20||t.getUTCDay()===0||t.getUTCDay()===6){t.setUTCDate(t.getUTCDate()+(t.getUTCHours()>=20?1:0));while(t.getUTCDay()===0||t.getUTCDay()===6)t.setUTCDate(t.getUTCDate()+1)}return`${t.getUTCFullYear()}${Rr(t.getUTCMonth()+1)}${Rr(t.getUTCDate())}`}function di(e){let t=ai.exec(e);if(!t)throw Error(`\u975E\u6CD5\u4EA4\u6613\u65E5: ${e}`);let r=Number(t[1]),n=Number(t[2]),i=Number(t[3]),o=Date.UTC(r,n-1,i),s=new Date(o);if(s.getUTCFullYear()!==r||s.getUTCMonth()!==n-1||s.getUTCDate()!==i)throw Error(`\u975E\u6CD5\u4EA4\u6613\u65E5: ${e}`);return Math.floor(o/1000)-28800}function xr(e,t){let r=e==="1d"?600:se[e]/60;return t*r+(r-1)}function Rr(e){return String(e).padStart(2,"0")}var ci=new Set(Ve);class Ue{timeframe;seconds;current=null;constructor(e){this.timeframe=e;if(!ci.has(e))throw Error(`\u5468\u671F "${e}" \u4E0D\u53D7\u652F\u6301\uFF1B\u4EC5\u652F\u6301 ${ve}`);this.seconds=se[e]}pushBar(e){let t=this.pushBars(e);if(t.length>1)throw Error("\u5355\u6839 1min bar \u540C\u65F6\u95ED\u5408\u4E86\u591A\u4E2A\u7A97\u53E3\uFF1B\u8BF7\u4F7F\u7528 pushBars() \u4FDD\u7559\u5168\u90E8\u4FE1\u53F7");return t[0]??null}pushBars(e){if(e.timeframe!=="1min")throw Error(`BarGenerator \u53EA\u63A5\u53D7\u95ED\u5408 1min bar\uFF0C\u6536\u5230 ${e.timeframe}`);if(this.seconds===60)return[e];let t=[],r=ze(e.barTime,this.timeframe,e.tradingDay);if(this.current&&this.current.barTime!==r){let o=this.finish();if(o)t.push(o)}if(!this.current)this.start(e,r);else this.merge(e);let n=this.timeframe!=="1d"&&e.barTime+60>=r+this.seconds,i=this.seconds>=3600?e.boundaryReason==="sessionEnd":e.boundaryReason!==void 0;if(n||i){let o=this.finish(e.boundaryReason);if(o)t.push(o)}return t}flush(e){return this.finish(e)}start(e,t){this.current={code:e.code,timeframe:this.timeframe,barTime:t,open:e.open,high:e.high,low:e.low,close:e.close,volume:e.volume,...e.tradingDay?{tradingDay:e.tradingDay}:{}}}merge(e){let t=this.current;if(t.high=Math.max(t.high,e.high),t.low=Math.min(t.low,e.low),t.close=e.close,t.volume+=e.volume,e.tradingDay)t.tradingDay=e.tradingDay}finish(e){let t=this.current;if(!t)return null;return this.current=null,{...t,...e?{boundaryReason:e}:{}}}}function _r(e){if(e.timeframe!=="1min")throw Error(`\u7B56\u7565\u9884\u70ED\u53EA\u63A5\u53D7\u95ED\u5408 1min Bar\uFF0C\u6536\u5230 ${e.timeframe}`)}function*Cr(e,t){if(t==="1min"){for(let o=0;o<e.length;o++)_r(e[o]),yield{startIndex:o,endIndex:o,triggerIndex:o};return}let r=new Ue(t),n=0,i=-1/0;for(let o=0;o<e.length;o++){let s=e[o];if(_r(s),s.barTime<i)throw Error("\u7B56\u7565\u9884\u70ED Bar \u5FC5\u987B\u6309\u65F6\u95F4\u5347\u5E8F\u6392\u5217");i=s.barTime;let a=ze(s.barTime,t,s.tradingDay);for(let d of r.pushBars(s)){let c=d.barTime===a?o:o-1;if(c<n)throw Error("\u7B56\u7565\u9884\u70ED Bar \u805A\u5408\u8FB9\u754C\u65E0\u6548");yield{startIndex:n,endIndex:c,triggerIndex:o},n=c+1}}}function Et(e,t){let r=0;for(let n of Cr(e,t))r++;return r}function ke(e,t,r){if(!Number.isInteger(r)||r<=0)throw Error("\u9884\u70ED Bar count \u5FC5\u987B\u4E3A\u6B63\u6574\u6570");let n=[...Cr(e,t)],i=n.length;if(i<r)return{bars:[...e],availableCount:i,selectedCount:i};let o=n[i-r];return{bars:e.slice(o.startIndex),availableCount:i,selectedCount:r}}var ui=new Set(["CFFEX","SHFE","CZCE","DCE","INE","GFEX"]);function K(e){let t=e.trim(),[r="",n,...i]=t.split(".");if(!r||!n||i.length>0)throw Error(`vtSymbol \u975E\u6CD5: ${e}`);if(!/^[A-Za-z][A-Za-z0-9]*$/.test(r)||!/\d/.test(r))throw Error(`vtSymbol \u5408\u7EA6\u4EE3\u7801\u975E\u6CD5: ${e}`);if(!ui.has(n.toUpperCase()))throw Error(`vtSymbol \u4EA4\u6613\u6240\u975E\u6CD5: ${e}`);let o=r.toUpperCase();return{instrumentID:o,vtSymbol:`${o}.${n.toUpperCase()}`}}function Pr(e){let t=e.split(".")[1]?.toUpperCase();return t==="SHFE"||t==="INE"}var li="20260105",mi=3500;function Y(e){if(!ae(e))throw Error("\u6D4B\u8BD5\u5B9A\u4E49 fixture \u5FC5\u987B\u662F\u5BF9\u8C61");if(Te(e,["vtSymbol","setting","instrument","commission","seedPrice","tradingDay"],"fixture"),typeof e.vtSymbol!=="string")throw Error("fixture.vtSymbol \u5FC5\u987B\u662F\u5B57\u7B26\u4E32");let t=K(e.vtSymbol);if(!ae(e.instrument))throw Error("fixture.instrument \u5FC5\u987B\u662F\u5BF9\u8C61");Te(e.instrument,["priceTick","size","name","minOrderVolume","maxOrderVolume","longMarginRatio","shortMarginRatio","isTrading"],"fixture.instrument");let r=E(e.instrument.priceTick,"fixture.instrument.priceTick"),n=x(e.instrument.size,"fixture.instrument.size"),i=e.instrument.name===void 0?t.instrumentID:e.instrument.name;if(typeof i!=="string")throw Error("fixture.instrument.name \u5FC5\u987B\u662F\u5B57\u7B26\u4E32");let o=x(e.instrument.minOrderVolume===void 0?1:e.instrument.minOrderVolume,"fixture.instrument.minOrderVolume"),s=x(e.instrument.maxOrderVolume===void 0?1e5:e.instrument.maxOrderVolume,"fixture.instrument.maxOrderVolume");if(s<o)throw Error("fixture.instrument.maxOrderVolume \u5FC5\u987B\u4E0D\u5C0F\u4E8E minOrderVolume");let a=Ee(e.instrument.longMarginRatio===void 0?0.1:e.instrument.longMarginRatio,"fixture.instrument.longMarginRatio"),d=Ee(e.instrument.shortMarginRatio===void 0?0.1:e.instrument.shortMarginRatio,"fixture.instrument.shortMarginRatio"),c=e.instrument.isTrading===void 0?!0:e.instrument.isTrading;if(typeof c!=="boolean")throw Error("fixture.instrument.isTrading \u5FC5\u987B\u662F\u5E03\u5C14\u503C");let u=e.commission===void 0?void 0:pi(e.commission),l=e.setting===void 0?{}:ce(e.setting,"fixture.setting"),f=e.seedPrice===void 0?mi:E(e.seedPrice,"fixture.seedPrice"),h=e.tradingDay===void 0?li:X(e.tradingDay),m=/^([A-Z]+)\d+([A-Z]+)$/.exec(t.instrumentID),v=m?`${m[1]}_${m[2]}`:t.instrumentID.match(/^[A-Z]+/)?.[0]??"";if(!v)throw Error(`\u65E0\u6CD5\u4ECE ${t.instrumentID} \u63A8\u5BFC fixture \u4EA7\u54C1\u4EE3\u7801`);return{vtSymbol:t.vtSymbol,instrumentID:t.instrumentID,exchangeID:t.vtSymbol.split(".")[1],productID:v,setting:l,priceTick:r,size:n,name:i,minOrderVolume:o,maxOrderVolume:s,longMarginRatio:a,shortMarginRatio:d,isTrading:c,commission:u,seedPrice:f,tradingDay:h}}function Ge(e){let t=e.commission;if(!t)return null;return{instrumentID:e.instrumentID,exchangeID:e.exchangeID,investorRange:"1",brokerID:"test",investorID:"test",bizType:"1",investUnitID:"",openRatioByMoney:t.open.ratioByMoney,openRatioByVolume:t.open.perLot,closeRatioByMoney:t.close.ratioByMoney,closeRatioByVolume:t.close.perLot,closeTodayRatioByMoney:t.closeToday.ratioByMoney,closeTodayRatioByVolume:t.closeToday.perLot}}function pi(e){if(!ae(e))throw Error("fixture.commission \u5FC5\u987B\u662F\u5BF9\u8C61");return Te(e,["open","close","closeToday"],"fixture.commission"),{open:It(e.open,"fixture.commission.open"),close:It(e.close,"fixture.commission.close"),closeToday:It(e.closeToday,"fixture.commission.closeToday")}}function It(e,t){if(!ae(e))throw Error(`${t} \u5FC5\u987B\u662F\u5BF9\u8C61`);return Te(e,["ratioByMoney","perLot"],t),{ratioByMoney:Ee(e.ratioByMoney,`${t}.ratioByMoney`),perLot:Ee(e.perLot,`${t}.perLot`)}}function Ie(e,t,r){let n=-1;for(let i of e){if(i.code!==r)throw Error("\u6D4B\u8BD5 Bar \u5408\u7EA6\u4E0E fixture \u4E0D\u5339\u914D");if(i.barTime<=n)throw Error("\u6D4B\u8BD5 Bar \u5FC5\u987B\u6309\u65F6\u95F4\u4E25\u683C\u9012\u589E");if((i.barTime+(i.boundaryReason?0:60))*1000>t)throw Error("\u6D4B\u8BD5 Bar \u5C1A\u672A\u95ED\u5408\uFF0C\u4E0D\u80FD\u4F7F\u7528\u672A\u6765\u6570\u636E");n=i.barTime}}function Ke(e){let t=e.tradingDay;return Date.parse(`${t.slice(0,4)}-${t.slice(4,6)}-${t.slice(6,8)}T09:00:00+08:00`)}function Ot(e){let t=new Date(e+28800000);return`${t.getUTCFullYear()}${String(t.getUTCMonth()+1).padStart(2,"0")}${String(t.getUTCDate()).padStart(2,"0")}`}function H(e,t,r,n=Ke(e)/1000+r*60){if(t.timeframe!==void 0&&t.timeframe!=="1min")throw Error("bar.timeframe \u5FC5\u987B\u662F 1min");let i=E(t.close,"bar.close"),o=t.open===void 0?i:E(t.open,"bar.open"),s=t.high===void 0?Math.max(o,i):E(t.high,"bar.high"),a=t.low===void 0?Math.min(o,i):E(t.low,"bar.low");if(s<Math.max(o,i)||a>Math.min(o,i))throw Error("Bar OHLC \u5173\u7CFB\u975E\u6CD5");let d=t.volume===void 0?100+r:Ee(t.volume,"bar.volume"),c=t.barTime===void 0?n:T(t.barTime,"bar.barTime");return{code:$r(t.code??e.instrumentID),timeframe:"1min",barTime:c,open:o,high:s,low:a,close:i,volume:d,tradingDay:t.tradingDay===void 0?e.tradingDay:X(t.tradingDay),...t.boundaryReason?{boundaryReason:t.boundaryReason}:{}}}function De(e,t,r,n=Ke(e)+r*60000){let i=E(t.lastPrice,"tick.lastPrice"),o=t.datetime===void 0?n:T(t.datetime,"tick.datetime"),s=new Date(o+28800000),a=t.updateTime??[s.getUTCHours(),s.getUTCMinutes(),s.getUTCSeconds()].map((c)=>String(c).padStart(2,"0")).join(":");if(!/^(?:[01]\d|2[0-3]):[0-5]\d:[0-5]\d$/.test(a))throw Error("tick.updateTime \u5FC5\u987B\u662F HH:MM:SS");let d=t.updateMillisec===void 0?o%1000:T(t.updateMillisec,"tick.updateMillisec");if(d>999)throw Error("tick.updateMillisec \u5FC5\u987B\u5728 0-999 \u4E4B\u95F4");return{code:$r(t.code??e.instrumentID),exchangeID:t.exchangeID??e.exchangeID,productID:t.productID??e.productID,priceTick:t.priceTick===void 0?e.priceTick:E(t.priceTick,"tick.priceTick"),lastPrice:i,updateTime:a,updateMillisec:d,actionDay:t.actionDay===void 0?Ot(o):X(t.actionDay),tradingDay:t.tradingDay===void 0?e.tradingDay:X(t.tradingDay),volume:t.volume===void 0?100+r:T(t.volume,"tick.volume"),datetime:o,bidPrice1:je(t,"bidPrice1",i,E),bidVolume1:je(t,"bidVolume1",1000,T),askPrice1:je(t,"askPrice1",i,E),askVolume1:je(t,"askVolume1",1000,T),...t.upperLimitPrice===void 0?{}:{upperLimitPrice:E(t.upperLimitPrice,"tick.upperLimitPrice")},...t.lowerLimitPrice===void 0?{}:{lowerLimitPrice:E(t.lowerLimitPrice,"tick.lowerLimitPrice")},...t.rawActionDay===void 0?{}:{rawActionDay:t.rawActionDay},...t.receivedAt===void 0?{}:{receivedAt:T(t.receivedAt,"tick.receivedAt")},...t.dateSource===void 0?{}:{dateSource:t.dateSource},...t.tradingDaySource===void 0?{}:{tradingDaySource:t.tradingDaySource}}}function $r(e){if(typeof e!=="string"||!/^[A-Za-z][A-Za-z0-9]*$/.test(e))throw Error("\u884C\u60C5 code \u975E\u6CD5");return e}function je(e,t,r,n){if(!Object.hasOwn(e,t))return r;return e[t]===void 0?void 0:n(e[t],`tick.${t}`)}function Ye(e){return{instrumentID:e.instrumentID,exchangeID:e.exchangeID,productID:e.productID,productClass:"1",exchangeInstID:e.instrumentID,instrumentName:e.name,volumeMultiple:e.size,priceTick:e.priceTick,maxLimitOrderVolume:e.maxOrderVolume,minLimitOrderVolume:e.minOrderVolume,maxMarketOrderVolume:0,minMarketOrderVolume:0,longMarginRatio:e.longMarginRatio,shortMarginRatio:e.shortMarginRatio,maxMarginSideAlgorithm:"",strikePrice:0,optionsType:"",combinationType:"",deliveryYear:0,deliveryMonth:0,createDate:"",openDate:"",expireDate:"",startDelivDate:"",endDelivDate:"",instLifePhase:"1",isTrading:e.isTrading?1:0,positionType:"",positionDateType:"",underlyingInstrID:"",underlyingMultiple:1}}function We(e){if(e===void 0)return de();if(!ae(e))throw Error("initialState.inventory \u5FC5\u987B\u662F\u5BF9\u8C61");return Te(e,["longToday","longYesterday","shortToday","shortYesterday"],"initialState.inventory"),{longToday:e.longToday===void 0?0:T(e.longToday,"longToday"),longYesterday:e.longYesterday===void 0?0:T(e.longYesterday,"longYesterday"),shortToday:e.shortToday===void 0?0:T(e.shortToday,"shortToday"),shortYesterday:e.shortYesterday===void 0?0:T(e.shortYesterday,"shortYesterday")}}function de(){return{longToday:0,longYesterday:0,shortToday:0,shortYesterday:0}}function Mr(e){return e.longToday+e.longYesterday-e.shortToday-e.shortYesterday}function gi(e,t){let r=new Date(Date.UTC(Number(e.slice(0,4)),Number(e.slice(4,6))-1,Number(e.slice(6,8))+t));return`${r.getUTCFullYear()}${String(r.getUTCMonth()+1).padStart(2,"0")}${String(r.getUTCDate()).padStart(2,"0")}`}function X(e){if(typeof e!=="string"||!/^\d{8}$/.test(e))throw Error("fixture.tradingDay \u5FC5\u987B\u662F YYYYMMDD");if(gi(e,0)!==e)throw Error(`fixture.tradingDay \u975E\u6CD5: ${e}`);return e}function ce(e,t){if(!ae(e))throw Error(`${t} \u5FC5\u987B\u662F\u5BF9\u8C61`);try{Dt(e,t,new Set);let r=JSON.stringify(e);if(r===void 0)throw Error("\u4E0D\u53EF\u5E8F\u5217\u5316");return JSON.parse(r)}catch(r){throw Error(`${t} \u5FC5\u987B\u53EF JSON \u5E8F\u5217\u5316: ${r instanceof Error?r.message:String(r)}`)}}function Dt(e,t,r){if(e===null||typeof e==="string"||typeof e==="boolean")return;if(typeof e==="number"){if(!Number.isFinite(e))throw Error(`${t} \u5305\u542B\u975E\u6709\u9650\u6570\u5B57`);return}if(typeof e!=="object")throw Error(`${t} \u5305\u542B\u4E0D\u53EF\u5E8F\u5217\u5316\u7684 ${typeof e}`);if(r.has(e))throw Error(`${t} \u5305\u542B\u5FAA\u73AF\u5F15\u7528`);if(r.add(e),Array.isArray(e))for(let n=0;n<e.length;n++)Dt(e[n],`${t}[${n}]`,r);else{let n=Object.getPrototypeOf(e);if(n!==Object.prototype&&n!==null)throw Error(`${t} \u5FC5\u987B\u662F\u666E\u901A\u5BF9\u8C61\u6216\u6570\u7EC4`);for(let[i,o]of Object.entries(e))Dt(o,`${t}.${i}`,r)}r.delete(e)}function Te(e,t,r){let n=Object.keys(e).find((i)=>!t.includes(i));if(n)throw Error(`${r} \u4E0D\u652F\u6301\u5B57\u6BB5 "${n}"`)}function E(e,t){if(typeof e!=="number"||!Number.isFinite(e)||e<=0)throw Error(`${t} \u5FC5\u987B\u662F\u6B63\u6570`);return e}function x(e,t){if(!Number.isSafeInteger(e)||e<=0)throw Error(`${t} \u5FC5\u987B\u662F\u6B63\u6574\u6570`);return e}function T(e,t){if(!Number.isSafeInteger(e)||e<0)throw Error(`${t} \u5FC5\u987B\u662F\u975E\u8D1F\u6574\u6570`);return e}function Ee(e,t){if(typeof e!=="number"||!Number.isFinite(e)||e<0)throw Error(`${t} \u5FC5\u987B\u662F\u975E\u8D1F\u6570`);return e}function ae(e){return e!==null&&typeof e==="object"&&!Array.isArray(e)}class Oe{fixture;sequence;now;observations;phase="running";instrument;orders=new Map;trades=new Map;reportedOrders=new Map;deliveredTrades=new Set;orderHandlers=new Set;tradeHandlers=new Set;errorHandlers=new Set;reconcileHandlers=new Set;faultHandlers=new Set;inventories=new Map;tradingDay;nextSubmitFailure;nextCancelFailure;holdingReports=!1;reportSequence=0;reports=new Map;pending=new Set;deliveredReports=new Set;constructor(e,t,r,n,i,o){this.fixture=e;this.sequence=r;this.now=n;this.observations=i;if(this.inventories.set(e.vtSymbol,{...t}),this.tradingDay=e.tradingDay,this.instrument=Ye(e),o)this.reconcile({...o,reason:"initial"})}snapshot(){return{phase:this.phase,tradingDay:this.tradingDay,inventory:{...this.inventories.get(this.fixture.vtSymbol)??de()},orders:[...this.orders.values()].map(L),trades:[...this.trades.values()].map((e)=>({...e}))}}holdReports(){this.holdingReports=!0}resumeReports(){this.requireConnected(),this.holdingReports=!1;for(let e of[...this.pending])this.deliverReport(e)}pendingReports(){return[...this.pending].map((e)=>structuredClone(this.reports.get(e)))}deliverReport(e){if(this.requireConnected(),!this.pending.delete(e))throw Error(`Pending broker report does not exist: ${e}`);this.deliver(this.reports.get(e))}repeatReport(e){this.requireConnected();let t=this.reports.get(e);if(!t||!this.deliveredReports.has(e))throw Error(`Delivered broker report does not exist: ${e}`);this.deliver(t,!0)}async prepareInstrument(e,t){if(e!==this.fixture.instrumentID||t!==this.fixture.exchangeID)throw Error(`\u6D4B\u8BD5\u5408\u7EA6\u4E0D\u5339\u914D: ${e}.${t}`);return this.instrument}async prepareCommission(e,t){if(e!==this.fixture.instrumentID||t!==this.fixture.exchangeID)throw Error(`\u6D4B\u8BD5\u624B\u7EED\u8D39\u5408\u7EA6\u4E0D\u5339\u914D: ${e}.${t}`)}getInstrument(e){return e===this.fixture.instrumentID?this.instrument:null}getCommission(e,t){if(e!==this.fixture.instrumentID||t!==this.fixture.exchangeID)return null;return Ge(this.fixture)}async queryPositions(e){return{phase:this.phase,positions:this.positionSnapshot().filter((t)=>!e||t.instrumentID===e.toUpperCase())}}async queryOrders(e){return[...this.orders.values()].filter((t)=>!e||t.instrumentID===e.toUpperCase()).map((t)=>L(t))}submitOrder(e){if(this.requireConnected(),this.nextSubmitFailure){let o=this.nextSubmitFailure;throw this.nextSubmitFailure=void 0,Error(o)}let t,r;do t=String(++this.sequence.order),r=`CTP.${this.tradingDay}.1.1.${t}`;while(this.orders.has(r));let n=e.direction==="buy"?"long":"short",i={vtOrderId:r,identity:{tradingDay:this.tradingDay,frontID:1,sessionID:1,orderRef:t,instrumentID:this.fixture.instrumentID,exchangeID:this.fixture.exchangeID},vtSymbol:this.fixture.vtSymbol,instrumentID:this.fixture.instrumentID,exchangeID:this.fixture.exchangeID,orderSysID:`TEST-${t}`,side:e.direction,direction:n,offset:e.offsetFlag,price:e.price,volume:e.volume,traded:0,status:"submitting",statusMessage:"",datetime:this.now()};return this.orders.set(r,i),this.reportedOrders.set(r,L(i)),this.observations.submissions.push({vtOrderId:r,direction:n,offset:e.offsetFlag,price:e.price,volume:e.volume}),this.observations.record("submission",this.observations.submissions.at(-1)),{vtOrderId:r,orderRef:t}}cancelOrder(e){if(this.observations.cancelRequests.push(e),this.observations.record("cancel",{vtOrderId:e}),this.requireConnected(),this.nextCancelFailure){let t=this.nextCancelFailure;throw this.nextCancelFailure=void 0,Error(t)}}onOrder(e){return this.orderHandlers.add(e),()=>this.orderHandlers.delete(e)}onTrade(e){return this.tradeHandlers.add(e),()=>this.tradeHandlers.delete(e)}onOrderError(e){return this.errorHandlers.add(e),()=>this.errorHandlers.delete(e)}onReconciled(e){return this.reconcileHandlers.add(e),()=>this.reconcileHandlers.delete(e)}onFault(e){return this.faultHandlers.add(e),()=>this.faultHandlers.delete(e)}failNextSubmit(e="test submit failed"){this.nextSubmitFailure=e}rejectSubmit(e,t="test submit rejected"){let r=this.requireActiveOrder(e);if(r.traded!==0||this.tradedVolume(e)>0)throw Error("\u5DF2\u6210\u4EA4\u59D4\u6258\u4E0D\u80FD\u62D2\u5355");if(r.status="rejected",r.statusMessage=t,this.phase!=="running")return;this.reportedOrders.set(e,L(r)),this.queueReport({type:"error",value:{vtOrderId:e,orderRef:r.identity.orderRef,instrumentID:r.instrumentID,operation:"submit",message:t}})}rejectCancel(e,t="test cancel rejected"){let r=this.requireOrder(e);this.requireConnected(),this.queueReport({type:"error",value:{vtOrderId:e,orderRef:r.identity.orderRef,instrumentID:r.instrumentID,operation:"cancel",message:t}})}emitExternalOrder(e){if(this.orders.has(e.vtOrderId))throw Error(`\u6D4B\u8BD5\u59D4\u6258\u5DF2\u5B58\u5728: ${e.vtOrderId}`);this.emitOrder(e)}emitOrder(e){let t=this.normalizeOrder(e);this.orders.set(t.vtOrderId,t),this.publishOrder(t)}emitTrade(e){let t=this.recordTrade(e);this.publishTrade(t)}disconnect(){if(this.phase!=="faulted")this.phase="recovering"}connect(){this.phase="running",this.reportedOrders.clear(),this.deliveredTrades.clear(),this.nextSubmitFailure=void 0,this.nextCancelFailure=void 0,this.pending.clear(),this.holdingReports=!1,this.reconcile({reason:"initial"})}reconcile(e={}){if(this.phase==="faulted")throw Error("\u6D4B\u8BD5 Broker \u5DF2 fault\uFF0C\u5FC5\u987B\u91CD\u542F Runtime");this.phase="recovering",this.pending.clear();try{let t=e.tradingDay===void 0?this.tradingDay:X(e.tradingDay);if(t<this.tradingDay)throw Error("\u6D4B\u8BD5 Broker TradingDay \u4E0D\u80FD\u56DE\u9000");if(t!==this.tradingDay)for(let o of this.inventories.values())o.longYesterday+=o.longToday,o.longToday=0,o.shortYesterday+=o.shortToday,o.shortToday=0;this.tradingDay=t;let r=e.orders===void 0?[...this.orders.values()].filter((o)=>o.identity.tradingDay===t).map(L):e.orders.map((o)=>this.normalizeOrder(o));if(e.orders!==void 0){for(let o of this.orders.values())if(o.identity.tradingDay===t)this.orders.delete(o.vtOrderId);for(let o of r)this.orders.set(o.vtOrderId,o)}for(let o of e.trades??[])this.recordTrade(o);if(e.inventory!==void 0)this.inventories.set(this.fixture.vtSymbol,We(e.inventory));let n=[...this.trades.values()].filter((o)=>o.tradingDay===t),i={reason:e.reason??"reconnect",tradingDay:t,accounts:[],positions:this.positionSnapshot(),orders:r,trades:n,recoveredAt:this.now()};if(i.reason==="reconnect"){for(let o of this.reportedOrders.values())if(w(o)&&o.identity.tradingDay===t&&!r.some((s)=>s.vtOrderId===o.vtOrderId))throw Error(`\u6D3B\u52A8\u59D4\u6258\u672A\u51FA\u73B0\u5728\u6062\u590D\u5FEB\u7167: ${o.vtOrderId}`);for(let o of r)this.publishOrder(o,!0);for(let o of n)this.publishTrade(o,!0)}else{for(let o of r)this.reportedOrders.set(o.vtOrderId,L(o));for(let o of n)this.deliveredTrades.add(o.vtTradeId)}for(let o of this.reconcileHandlers)o(i);this.phase="running"}catch(t){throw this.fault(t instanceof Error?t.message:String(t)),t}}fault(e="test gateway fault"){if(this.phase==="faulted")return;this.phase="faulted";for(let t of this.faultHandlers)t(e)}acknowledge(e){this.updateOrder(e,(t)=>{if(t.traded!==0||this.tradedVolume(e)>0)throw Error("\u5DF2\u6210\u4EA4\u59D4\u6258\u4E0D\u80FD\u91CD\u65B0\u786E\u8BA4");t.status="notTraded",t.statusMessage="test acknowledged"})}partialFill(e,t,r){this.fillVolume(e,t,r)}fill(e,t){let r=this.requireActiveOrder(e);this.fillVolume(e,r.volume-Math.max(r.traded,this.tradedVolume(e)),t)}reject(e,t="test rejected"){this.updateOrder(e,(r)=>{if(r.traded!==0||this.tradedVolume(e)>0)throw Error("\u5DF2\u6210\u4EA4\u59D4\u6258\u4E0D\u80FD\u62D2\u5355");r.status="rejected",r.statusMessage=t})}cancel(e,t="test cancelled"){this.updateOrder(e,(r)=>{r.traded=Math.max(r.traded,this.tradedVolume(e)),r.status="cancelled",r.statusMessage=t})}failNextCancel(e="test cancel failed"){this.nextCancelFailure=e}settleActiveOrders(){for(let e of[...this.orders.values()])if(e.status==="submitting"||e.status==="notTraded"||e.status==="partTraded")this.cancel(e.vtOrderId,"test cleanup")}fillVolume(e,t,r){if(!Number.isInteger(t)||t<=0)throw Error("\u6210\u4EA4\u6570\u91CF\u5FC5\u987B\u662F\u6B63\u6574\u6570");let n=this.requireActiveOrder(e),i=n.volume-Math.max(n.traded,this.tradedVolume(e));if(t>i)throw Error(`\u6210\u4EA4\u6570\u91CF ${t} \u8D85\u8FC7\u5269\u4F59\u6570\u91CF ${i}`);let o=E(r??n.price,"\u6210\u4EA4\u4EF7\u683C");n.traded=n.volume-i+t,n.status=n.traded===n.volume?"allTraded":"partTraded",n.statusMessage="test filled",this.publishOrder(n);let s;do s=`TESTTRADE.${++this.sequence.trade}`;while(this.trades.has(s));this.emitTrade({vtTradeId:s,vtOrderId:n.vtOrderId,price:o,volume:t,datetime:this.now(),tradingDay:this.tradingDay})}updateOrder(e,t){let r=this.requireActiveOrder(e);t(r),this.publishOrder(r)}normalizeOrder(e){let t=this.orders.get(e.vtOrderId),r=hi({...this.fixture,tradingDay:this.tradingDay},{...e,vtSymbol:e.vtSymbol??t?.vtSymbol},this.now());if(t){if(t.vtSymbol!==r.vtSymbol||t.direction!==r.direction||t.offset!==r.offset||t.volume!==r.volume)throw Error(`\u6D4B\u8BD5\u59D4\u6258\u8EAB\u4EFD\u5B57\u6BB5\u53D1\u751F\u53D8\u5316: ${r.vtOrderId}`);if(r.identity={...t.identity},r.orderSysID=t.orderSysID,r.traded<t.traded||Ar(r)<Ar(t))return L(t)}return r}tradedVolume(e){let t=0;for(let r of this.trades.values())if(r.vtOrderId===e)t+=r.volume;return t}recordTrade(e){if(typeof e.vtTradeId!=="string"||!e.vtTradeId.trim())throw Error("\u6D4B\u8BD5\u6210\u4EA4 ID \u4E0D\u80FD\u4E3A\u7A7A");let t=this.trades.get(e.vtTradeId);if(t)return t;let r=this.requireOrder(e.vtOrderId),n=x(e.volume,"\u6210\u4EA4\u6570\u91CF"),i=this.tradedVolume(r.vtOrderId)+n;if(i>r.volume||!w(r)&&i>r.traded)throw Error("\u6D4B\u8BD5\u6210\u4EA4\u6570\u91CF\u8D85\u8FC7\u59D4\u6258\u5B9E\u9645\u6210\u4EA4\u8303\u56F4");let o={vtTradeId:e.vtTradeId,vtOrderId:r.vtOrderId,vtSymbol:r.vtSymbol,instrumentID:r.instrumentID,exchangeID:r.exchangeID,orderSysID:r.orderSysID,tradeID:e.vtTradeId,side:r.side,direction:r.direction,offset:r.offset,price:E(e.price??r.price,"\u6210\u4EA4\u4EF7\u683C"),volume:n,datetime:e.datetime===void 0?this.now():T(e.datetime,"\u6210\u4EA4\u65F6\u95F4"),tradingDay:e.tradingDay===void 0?this.tradingDay:X(e.tradingDay)};if(o.tradingDay!==this.tradingDay)throw Error("\u6D4B\u8BD5\u6210\u4EA4 TradingDay \u4E0E Broker \u4E0D\u4E00\u81F4");this.trades.set(o.vtTradeId,o);let s=this.inventories.get(o.vtSymbol)??de();return this.inventories.set(o.vtSymbol,s),yi(s,o.direction,o.offset,o.volume),o}positionSnapshot(){return[...this.inventories].flatMap(([e,t])=>fi({...this.fixture,...K(e),exchangeID:e.split(".")[1],tradingDay:this.tradingDay},t))}publishOrder(e,t=!1){if(!t&&this.phase!=="running")return;this.queueReport({type:"order",value:L(e)},t)}publishTrade(e,t=!1){if(!t&&this.phase!=="running")return;this.queueReport({type:"trade",value:{...e}},t)}queueReport(e,t=!1){let r={...e,id:`report-${++this.reportSequence}`,createdAt:this.now()};if(this.reports.set(r.id,r),this.observations.record("broker",{operation:"queued",report:r}),!this.holdingReports||t)this.deliver(r);else this.pending.add(r.id)}deliver(e,t=!1){if(this.deliveredReports.add(e.id),this.observations.record("broker",{operation:"delivered",duplicate:t,report:e}),e.type==="trade"){let i=e.value;if(!t&&this.deliveredTrades.has(i.vtTradeId))return;this.deliveredTrades.add(i.vtTradeId);for(let o of this.tradeHandlers)o({...i});return}if(e.type==="error"){for(let i of this.errorHandlers)i({...e.value});return}let r=e.value,n=this.reportedOrders.get(r.vtOrderId);if(!t&&n&&n.status===r.status&&n.traded===r.traded&&n.statusMessage===r.statusMessage&&n.orderSysID===r.orderSysID)return;this.reportedOrders.set(r.vtOrderId,L(r));for(let i of this.orderHandlers)i(L(r))}requireConnected(){if(this.phase!=="running")throw Error(`\u6D4B\u8BD5 Broker \u672A\u5C31\u7EEA: ${this.phase}`)}requireOrder(e){let t=this.orders.get(e);if(!t)throw Error(`\u6D4B\u8BD5\u59D4\u6258\u4E0D\u5B58\u5728: ${e}`);return t}requireActiveOrder(e){let t=this.requireOrder(e);if(!w(t))throw Error(`\u6D4B\u8BD5\u59D4\u6258\u5DF2\u7EC8\u6B62: ${e} (${t.status})`);return t}}function Ar(e){if(e.status==="submitting")return 0;if(e.status==="notTraded")return 1;if(e.status==="partTraded")return 2;return 3}function hi(e,t,r){if(typeof t.vtOrderId!=="string"||!t.vtOrderId.trim())throw Error("\u6D4B\u8BD5\u59D4\u6258 ID \u4E0D\u80FD\u4E3A\u7A7A");let{vtSymbol:n,instrumentID:i}=K(t.vtSymbol??e.vtSymbol),o=n.split(".")[1];if(t.direction!=="long"&&t.direction!=="short")throw Error("\u6D4B\u8BD5\u59D4\u6258\u65B9\u5411\u975E\u6CD5");let s=t.offset??"open";if(!["open","close","closeToday","closeYesterday"].includes(s))throw Error("\u6D4B\u8BD5\u59D4\u6258\u5F00\u5E73\u975E\u6CD5");let a=x(t.volume,"\u6D4B\u8BD5\u59D4\u6258\u6570\u91CF"),d=t.traded===void 0?0:T(t.traded,"\u6D4B\u8BD5\u59D4\u6258\u5DF2\u6210\u4EA4\u6570\u91CF"),c=t.status??"notTraded";if(!["submitting","notTraded","partTraded","allTraded","cancelled","rejected"].includes(c)||d>a||(c==="submitting"||c==="notTraded"||c==="rejected")&&d!==0||c==="partTraded"&&(d===0||d===a)||c==="allTraded"&&d!==a)throw Error("\u6D4B\u8BD5\u59D4\u6258\u72B6\u6001\u4E0E\u6210\u4EA4\u6570\u91CF\u4E0D\u4E00\u81F4");return{vtOrderId:t.vtOrderId,identity:{tradingDay:e.tradingDay,frontID:1,sessionID:1,orderRef:t.vtOrderId.split(".").at(-1),instrumentID:i,exchangeID:o},vtSymbol:n,instrumentID:i,exchangeID:o,orderSysID:`TEST-${t.vtOrderId}`,side:t.direction==="long"?"buy":"sell",direction:t.direction,offset:s,price:E(t.price,"\u6D4B\u8BD5\u59D4\u6258\u4EF7\u683C"),volume:a,traded:d,status:c,statusMessage:t.statusMessage??"",datetime:t.datetime===void 0?r:T(t.datetime,"\u6D4B\u8BD5\u59D4\u6258\u65F6\u95F4")}}function fi(e,t){let r=[],n=(i,o,s)=>{if(o+s===0)return;r.push({instrumentID:e.instrumentID,exchangeID:e.exchangeID,vtSymbol:e.vtSymbol,direction:i,hedgeFlag:"1",investUnitID:"",tradingDay:e.tradingDay,volume:o+s,todayVolume:o,yesterdayVolume:s,frozen:0,price:e.seedPrice,pnl:0,margin:0,positionCost:0})};return n("long",t.longToday,t.longYesterday),n("short",t.shortToday,t.shortYesterday),r}function yi(e,t,r,n){if(r==="open"){if(t==="long")e.longToday+=n;else e.shortToday+=n;return}let i=t==="short"?"longToday":"shortToday",o=t==="short"?"longYesterday":"shortYesterday";if(r==="closeToday")e[i]=Math.max(0,e[i]-n);else if(r==="closeYesterday")e[o]=Math.max(0,e[o]-n);else{let s=Math.min(e[o],n);e[o]-=s,e[i]=Math.max(0,e[i]-(n-s))}}function L(e){return{...e,identity:{...e.identity}}}class Qe extends Error{method;code;constructor(e,t,r){super(r);this.method=e;this.code=t;this.name="GatewayRpcError"}}var Je=(e)=>e.toUpperCase();function Re(e){return e.map((t)=>({...t,instrumentID:Je(t.instrumentID)}))}class Rt{transport;loginResult=null;connected=!1;queryQueue=Promise.resolve();lastQueryAt=0;minQueryIntervalMs;queryTimeoutMs;normalizeInstrumentID;cleanups;pendingQueries=new Set;disposed=!1;clock;constructor(e,t={}){this.transport=e;this.minQueryIntervalMs=t.minQueryIntervalMs??0,this.queryTimeoutMs=t.queryTimeoutMs??15000,this.normalizeInstrumentID=t.normalizeInstrumentID??((r)=>r),this.clock=t.clock??{now:Date.now,schedule:(r,n)=>{let i=setTimeout(r,n);return()=>clearTimeout(i)}},this.cleanups=[e.on("onDisconnected",()=>{this.connected=!1}),e.on("onReconnecting",()=>{this.connected=!1}),e.on("onReconnected",(r)=>{this.connected=!0,this.loginResult=r.params}),e.onExit(()=>{this.connected=!1})]}async login(e){let t=await this.request("login",e,"\u4EA4\u6613\u767B\u5F55\u5931\u8D25");return this.loginResult=t,this.connected=!0,t}async logout(e,t){await this.request("logout",{broker:e,user:t},"\u767B\u51FA\u5931\u8D25"),this.loginResult=null,this.connected=!1}async changePassword(e){await this.request("changePassword",e,"\u4FEE\u6539\u5BC6\u7801\u5931\u8D25")}async insertOrder(e){let t=this.loginResult,r=await this.request("insertOrder",this.normalizeParams(e),"\u4E0B\u5355\u5931\u8D25"),n=r.tradingDay??t?.tradingDay,i=r.frontID??t?.frontID,o=r.sessionID??t?.sessionID;if(!n||!i||!o)throw Error("\u4E0B\u5355\u6210\u529F\u4F46\u4EA4\u6613\u4F1A\u8BDD\u8EAB\u4EFD\u4E0D\u53EF\u7528");return{tradingDay:n,frontID:i,sessionID:o,orderRef:r.orderRef,requestID:r.requestID}}cancelOrder(e){return this.request("cancelOrder",this.normalizeParams(e),"\u64A4\u5355\u5931\u8D25")}queryAccount(e,t){return this.query(()=>this.requestAndWait("queryAccount",{broker:e,investorId:t},"onQueryAccountResult",(r)=>r.accounts??[],"\u67E5\u8BE2\u8D26\u6237\u5931\u8D25",!0))}queryPositions(e,t,r){return this.query(()=>this.requestAndWait("queryPosition",{broker:e,investorId:t,instrumentID:r?this.normalizeInstrumentID(r):""},"onQueryPositionResult",(n)=>Re(n.positions??[]),"\u67E5\u8BE2\u6301\u4ED3\u5931\u8D25",!0))}queryOrders(e){return this.query(()=>this.requestAndWait("queryOrder",this.normalizeParams(e),"onQueryOrderResult",(t)=>Re(t.orders??[]),"\u67E5\u8BE2\u59D4\u6258\u5931\u8D25",!0))}queryTrades(e){return this.query(()=>this.requestAndWait("queryTrade",this.normalizeParams(e),"onQueryTradeResult",(t)=>Re(t.trades??[]),"\u67E5\u8BE2\u6210\u4EA4\u5931\u8D25",!0))}querySettlementInfo(e){return this.query(()=>this.requestAndWait("querySettlementInfo",e,"onQuerySettlementInfoResult",(t)=>t.settlementInfos??t.settlements??[],"\u67E5\u8BE2\u7ED3\u7B97\u5355\u5931\u8D25",!0))}queryInstrument(e={}){return this.query(()=>this.requestAndWait("queryInstrument",this.normalizeParams(e),"onQueryInstrumentResult",(t)=>Re(t.instruments??[]),"\u67E5\u8BE2\u5408\u7EA6\u89C4\u683C\u5931\u8D25",!0,e.instrumentID||e.exchangeID||e.exchangeInstID||e.productID?this.queryTimeoutMs:60000))}queryCommissionRates(e){return this.query(()=>this.requestAndWait("queryInstrumentCommissionRate",this.normalizeParams(e),"onQueryCommissionRateResult",(t)=>Re(t.commissionRates??[]),"\u67E5\u8BE2\u624B\u7EED\u8D39\u7387\u5931\u8D25",!0,e.instrumentID?this.queryTimeoutMs:60000))}async queryCommissionRate(e){return(await this.queryCommissionRates(e))[0]??null}onOrder(e){return this.transport.on("onOrder",(t)=>{let r=t.params;e({...r,instrumentID:Je(r.instrumentID)})})}onTrade(e){return this.transport.on("onTrade",(t)=>{let r=t.params;e({...r,instrumentID:Je(r.instrumentID)})})}onOrderError(e){return this.transport.on("onOrderError",(t)=>{let r=t.params;e({...r,instrumentID:r.instrumentID?Je(r.instrumentID):void 0})})}onConnection(e,t){return this.transport.on(e,t)}dispose(){this.disposed=!0;for(let e of[...this.pendingQueries])e();for(let e of this.cleanups.splice(0))e()}query(e){let t=this.queryQueue.then(async()=>{if(this.disposed)throw Error("Trader gateway API disposed");let r=Math.max(0,this.minQueryIntervalMs-(this.clock.now()-this.lastQueryAt));if(r>0)await new Promise((n,i)=>{let o=()=>{s(),this.pendingQueries.delete(o),i(Error("Trader gateway API disposed"))},s=this.clock.schedule(()=>{this.pendingQueries.delete(o),n()},r);this.pendingQueries.add(o)});if(this.disposed)throw Error("Trader gateway API disposed");try{return await e()}finally{this.lastQueryAt=this.clock.now()}});return this.queryQueue=t.then(()=>{return},()=>{return}),t}requestAndWait(e,t,r,n,i,o=!1,s=this.queryTimeoutMs){return new Promise((a,d)=>{let c=null,u=null,l=null,f=[],h=()=>{c?.(),c=null,u?.(),u=null,this.pendingQueries.delete(m)},m=()=>{h(),d(Error("Trader gateway API disposed"))};this.pendingQueries.add(m),c=this.clock.schedule(()=>{h(),d(Error(`${e} \u67E5\u8BE2\u8D85\u65F6`))},s);let v=(p)=>{h();let k=p.params;if(k.ok===!1)d(Error(k.error??`${e} \u67E5\u8BE2\u5931\u8D25`));else a(n(p.params))};u=this.transport.on(r,(p)=>{if(!o){v(p);return}if(l===null){f.push(p);return}if(p.params.requestID===l)v(p)}),this.transport.request(e,t).then((p)=>{if(!p.ok){h(),d(Error(p.error?.msg??i));return}if(o){let k=p.data?.requestID;if(!Number.isInteger(k)){h(),d(Error(`${e} \u672A\u8FD4\u56DE\u6709\u6548 requestID`));return}l=k;let V=f.find((M)=>M.params.requestID===l);if(V)v(V)}}).catch((p)=>{h(),d(p)})})}async request(e,t,r){let n=await this.transport.request(e,t);if(!n.ok)throw new Qe(e,n.error?.code,n.error?.msg??r);return n.data}normalizeParams(e){if(!e.instrumentID&&!e.productID)return e;return{...e,...e.instrumentID?{instrumentID:this.normalizeInstrumentID(e.instrumentID)}:{},...e.productID?{productID:this.normalizeInstrumentID(e.productID)}:{}}}}var wi=28800000,Si=Number.MAX_VALUE/2,Br=1e5;class Ct extends Error{}function b(e,t){let r=e?.trim()??"";if(!r)throw Error(`${t} \u4E3A\u7A7A`);return r}function vi(e){if(!/^\d{8}$/.test(e))return!1;let t=Number(e.slice(0,4)),r=Number(e.slice(4,6)),n=Number(e.slice(6,8)),i=new Date(Date.UTC(t,r-1,n));return i.getUTCFullYear()===t&&i.getUTCMonth()===r-1&&i.getUTCDate()===n}function _(e,t){let r=e?.trim()??"";if(!vi(r))throw Error(`${t} \u975E\u6CD5: ${r}`);return r}function N(e,t){if(!Number.isInteger(e)||e<0)throw Error(`${t} \u975E\u6CD5: ${e}`);return e}function Xe(e,t){if(!Number.isInteger(e)||e<-2147483648||e>2147483647)throw Error(`${t} \u975E\u6CD5: ${e}`);return e}function Ze(e,t){if(!Number.isFinite(e))throw Error(`${t} \u975E\u6CD5: ${e}`);return e}function Pt(e,t){if(!Number.isFinite(e)||e<=0||e>=Si)throw Error(`${t} \u975E\u6CD5: ${e}`);return e}function $t(e,t){if(!Number.isInteger(e)||e<=0)throw Error(`${t} \u975E\u6CD5: ${e}`);return e}function Nr(e,t,r){let n=_(e,`${r}\u65E5\u671F`),i=/^(\d{2}):(\d{2}):(\d{2})$/.exec(t);if(!i)throw Error(`${r}\u65F6\u95F4\u975E\u6CD5: ${t}`);let o=Number(i[1]),s=Number(i[2]),a=Number(i[3]);if(o>23||s>59||a>59)throw Error(`${r}\u65F6\u95F4\u975E\u6CD5: ${t}`);return Date.UTC(Number(n.slice(0,4)),Number(n.slice(4,6))-1,Number(n.slice(6,8)),o,s,a)-wi}function Fr(e){if(e==="0")return{side:"buy",direction:"long"};if(e==="1")return{side:"sell",direction:"short"};throw Error(`CTP Direction \u4E0D\u652F\u6301: ${e}`)}function qr(e){switch(e){case"0":return"open";case"1":return"close";case"3":return"closeToday";case"4":return"closeYesterday";default:throw Error(`CTP OffsetFlag \u4E0D\u652F\u6301: ${e}`)}}function ki(e){if(!["0","1","2","3","4","5","6"].includes(e.orderSubmitStatus))throw Error(`CTP OrderSubmitStatus \u4E0D\u652F\u6301: ${e.orderSubmitStatus}`);if(e.orderSubmitStatus==="4")return"rejected";switch(e.orderStatus){case"0":return"allTraded";case"1":return"partTraded";case"2":case"4":case"5":return"cancelled";case"3":case"b":case"c":return"notTraded";case"a":return"submitting";default:throw Error(`CTP OrderStatus \u4E0D\u652F\u6301: ${e.orderStatus}`)}}function Hr(e,t){return`${e}|${t}`}function Lr(e,t){return`${e}|${t}`}function _t(e){let t=_(e.tradingDay,"\u59D4\u6258 TradingDay"),r=N(e.frontID,"\u59D4\u6258 FrontID"),n=Xe(e.sessionID,"\u59D4\u6258 SessionID"),i=b(e.orderRef,"\u59D4\u6258 OrderRef");return`CTP.${t}.${r}.${n}.${i}`}function xt(e){let t=b(e.instrumentID,"\u59D4\u6258 InstrumentID").toUpperCase(),r=b(e.exchangeID,"\u59D4\u6258 ExchangeID").toUpperCase(),n=_(e.tradingDay,"\u59D4\u6258 TradingDay"),i=b(e.orderRef,"\u59D4\u6258 OrderRef"),o={tradingDay:n,frontID:N(e.frontID,"\u59D4\u6258 FrontID"),sessionID:Xe(e.sessionID,"\u59D4\u6258 SessionID"),orderRef:i,instrumentID:t,exchangeID:r},s=Fr(e.direction),a=$t(e.volumeTotalOriginal,"\u59D4\u6258\u6570\u91CF"),d=N(e.volumeTraded,"\u59D4\u6258\u6210\u4EA4\u6570\u91CF");if(d>a)throw Error(`\u59D4\u6258\u6210\u4EA4\u6570\u91CF\u5927\u4E8E\u59D4\u6258\u6570\u91CF: ${d}/${a}`);return{vtOrderId:_t(o),identity:o,vtSymbol:`${t}.${r}`,instrumentID:t,exchangeID:r,orderSysID:e.orderSysID.trim(),...s,offset:qr(e.combOffsetFlag),price:Pt(e.limitPrice,"\u59D4\u6258\u4EF7\u683C"),volume:a,traded:d,status:ki(e),statusMessage:e.statusMsg,datetime:Nr(e.insertDate,e.insertTime,"\u59D4\u6258"),...e.traceId?{traceId:e.traceId}:{}}}function Ti(e,t,r){let n=b(e.instrumentID,"\u6210\u4EA4 InstrumentID").toUpperCase(),i=b(e.exchangeID,"\u6210\u4EA4 ExchangeID").toUpperCase(),o=_(e.tradingDay||r,"\u6210\u4EA4 TradingDay"),s=b(e.orderSysID,"\u6210\u4EA4 OrderSysID"),a=b(e.orderRef,"\u6210\u4EA4 OrderRef"),d=t(i,s,o,a);if(!d)throw new Ct(`\u6210\u4EA4\u65E0\u6CD5\u5173\u8054\u59D4\u6258: ${i}/${s}/${a}`);let c=b(e.tradeID,"\u6210\u4EA4 TradeID"),u=Fr(e.direction);return{vtTradeId:`CTP.${o}.${i}.${c}`,vtOrderId:d,vtSymbol:`${n}.${i}`,instrumentID:n,exchangeID:i,orderSysID:s,tradeID:c,...u,offset:qr(e.offsetFlag),price:Pt(e.price,"\u6210\u4EA4\u4EF7\u683C"),volume:$t(e.volume,"\u6210\u4EA4\u6570\u91CF"),datetime:Nr(e.tradeDate,e.tradeTime,"\u6210\u4EA4"),tradingDay:o,...e.traceId?{traceId:e.traceId}:{}}}function Ei(e,t=new Map){let r=new Map;for(let n of e){let i=b(n.instrumentID,"\u6301\u4ED3 InstrumentID").toUpperCase(),o=b(n.exchangeID,`\u6301\u4ED3 ${i} ExchangeID`).toUpperCase(),s=N(n.position,`\u6301\u4ED3 ${i} Position`),a=N(n.todayPosition,`\u6301\u4ED3 ${i} TodayPosition`);if(N(n.ydPosition,`\u6301\u4ED3 ${i} YdPosition`),a>s)throw Error(`\u6301\u4ED3 ${i} TodayPosition \u5927\u4E8E Position`);if(n.positionDate!=="1"&&n.positionDate!=="2")throw Error(`\u6301\u4ED3 ${i} PositionDate \u4E0D\u652F\u6301: ${n.positionDate}`);if(n.direction==="1"){if(s!==0)throw Error(`\u6682\u4E0D\u652F\u6301\u51C0\u6301\u4ED3\u8BB0\u5F55: ${i}`);continue}let d=n.direction==="2"?"long":n.direction==="3"?"short":(()=>{throw Error(`\u6301\u4ED3 ${i} PosiDirection \u4E0D\u652F\u6301: ${n.direction}`)})(),c=b(n.hedgeFlag,`\u6301\u4ED3 ${i} HedgeFlag`),u=n.investUnitID.trim(),l=_(n.tradingDay,`\u6301\u4ED3 ${i} TradingDay`),f=`${i}|${o}|${d}|${c}|${u}`,h=r.get(f);if(!h)h={instrumentID:i,exchangeID:o,direction:d,hedgeFlag:c,investUnitID:u,tradingDay:l,volume:0,yesterdayVolume:0,frozen:0,pnl:0,margin:0,positionCost:0},r.set(f,h);else if(h.tradingDay!==l)throw Error(`\u6301\u4ED3 ${i} \u6DF7\u5165\u591A\u4E2A TradingDay`);if(h.volume+=s,o==="SHFE"||o==="INE"){if(n.ydPosition>0&&a===0)h.yesterdayVolume+=s}else h.yesterdayVolume+=s-a;h.frozen+=d==="long"?N(n.shortFrozen,`\u6301\u4ED3 ${i} ShortFrozen`):N(n.longFrozen,`\u6301\u4ED3 ${i} LongFrozen`),h.pnl+=Ze(n.positionProfit,`\u6301\u4ED3 ${i} PositionProfit`),h.margin+=Ze(n.useMargin,`\u6301\u4ED3 ${i} UseMargin`),h.positionCost+=Ze(n.positionCost,`\u6301\u4ED3 ${i} PositionCost`)}return[...r.values()].map((n)=>{if(n.yesterdayVolume>n.volume)throw Error(`\u6301\u4ED3 ${n.instrumentID} \u6628\u4ED3\u5927\u4E8E\u603B\u4ED3`);let i=t.get(n.instrumentID)?.volumeMultiple??0,o=n.volume>0&&i>0?n.positionCost/(n.volume*i):0;return{instrumentID:n.instrumentID,exchangeID:n.exchangeID,vtSymbol:`${n.instrumentID}.${n.exchangeID}`,direction:n.direction,hedgeFlag:n.hedgeFlag,investUnitID:n.investUnitID,tradingDay:n.tradingDay,volume:n.volume,todayVolume:n.volume-n.yesterdayVolume,yesterdayVolume:n.yesterdayVolume,frozen:n.frozen,price:o,pnl:n.pnl,margin:n.margin,positionCost:n.positionCost}})}function U(e){return e.status==="submitting"||e.status==="notTraded"||e.status==="partTraded"}class Mt{api;options;contracts=new Map;orders=new Map;orderIdBySys=new Map;orderIdByRef=new Map;ambiguousOrderRefs=new Set;seenTrades=new Set;tradeLedgerDay="";pendingCancels=new Set;unresolvedTrades=[];pendingEvents=[];orderHandlers=new Set;tradeHandlers=new Set;errorHandlers=new Set;phaseHandlers=new Set;reconcileHandlers=new Set;faultHandlers=new Set;cleanups=[];session=null;currentSnapshot=null;recoveryTask=null;recoveryObservedOrderIds=null;_phase="idle";constructor(e,t){this.api=e;this.options=t;b(t.broker,"\u9002\u914D\u5668 BrokerID"),b(t.investorId,"\u9002\u914D\u5668 InvestorID"),this.cleanups.push(e.onOrder((r)=>this.receive({kind:"order",value:r})),e.onTrade((r)=>this.receive({kind:"trade",value:r})),e.onOrderError((r)=>this.receive({kind:"error",value:r})),e.onConnection("onDisconnected",()=>this.beginRecovery()),e.onConnection("onReconnecting",()=>this.beginRecovery()),e.onConnection("onReconnected",(r)=>{try{let n=r.params;this.setSession(n),this.reconcile(!0).catch((i)=>this.fail(i))}catch(n){this.fail(n)}}),e.transport.on("onReconnectFailed",(r)=>{this.fail(Error(String(r.params.error??"CTP \u91CD\u8FDE\u5931\u8D25")))}))}get phase(){return this._phase}get snapshot(){return this.currentSnapshot}async initialize(e){return this.setSession(e),this.reconcile(!1)}registerInstrument(e){this.contracts.set(e.instrumentID.toUpperCase(),e)}async queryPositions(e){this.ensureReady();let t=await this.api.queryPositions(this.options.broker,this.options.investorId,e);return this.normalizePositions(t)}async queryOrders(e){this.ensureReady();let r=(await this.api.queryOrders({broker:this.options.broker,investorId:this.options.investorId,instrumentID:e})).map((i)=>(this.validateOwner(i,"\u59D4\u6258"),this.acceptOrder(xt(i),!1))),n=new Map(this.cachedOrders(e).map((i)=>[i.vtOrderId,i]));for(let i of r)n.set(i.vtOrderId,i);return[...n.values()].sort((i,o)=>o.datetime-i.datetime)}cachedOrders(e){let t=e?.toUpperCase();return[...this.orders.values()].filter((r)=>!t||r.instrumentID===t).sort((r,n)=>n.datetime-r.datetime)}async queryAccounts(){this.ensureReady();let e=await this.api.queryAccount(this.options.broker,this.options.investorId);return this.validateAccounts(e,this.requireSession().tradingDay),e}async queryTrades(e){return this.ensureReady(),(await this.api.queryTrades({broker:this.options.broker,investorId:this.options.investorId,instrumentID:e})).map((r)=>(this.validateOwner(r,"\u6210\u4EA4"),this.normalizeTrade(r)))}submitOrder(e){if(this.ensureReady(),e.direction!=="buy"&&e.direction!=="sell")throw Error(`\u59D4\u6258\u65B9\u5411\u4E0D\u652F\u6301: ${String(e.direction)}`);if(!["open","close","closeToday","closeYesterday"].includes(e.offsetFlag))throw Error(`\u59D4\u6258\u5F00\u5E73\u4E0D\u652F\u6301: ${String(e.offsetFlag)}`);Pt(e.price,"\u59D4\u6258\u4EF7\u683C"),$t(e.volume,"\u59D4\u6258\u6570\u91CF");let t=this.requireSession(),r={tradingDay:_(t.tradingDay,"\u767B\u5F55 TradingDay"),frontID:N(t.frontID,"\u767B\u5F55 FrontID"),sessionID:Xe(t.sessionID,"\u767B\u5F55 SessionID"),orderRef:b(e.orderRef,"\u59D4\u6258 OrderRef"),instrumentID:b(e.instrumentID,"\u59D4\u6258 InstrumentID").toUpperCase(),exchangeID:b(e.exchangeID,"\u59D4\u6258 ExchangeID").toUpperCase()},n=_t(r);return this.bindOrderRef(r.tradingDay,r.orderRef,n),this.orders.set(n,{vtOrderId:n,identity:r,vtSymbol:`${r.instrumentID}.${r.exchangeID}`,instrumentID:r.instrumentID,exchangeID:r.exchangeID,orderSysID:"",side:e.direction,direction:e.direction==="buy"?"long":"short",offset:e.offsetFlag,price:e.price,volume:e.volume,traded:0,status:"submitting",statusMessage:"",datetime:(this.options.now??Date.now)(),...e.traceId?{traceId:e.traceId}:{}}),this.api.insertOrder(e).then((i)=>{if(i.tradingDay!==r.tradingDay||i.frontID!==r.frontID||i.sessionID!==r.sessionID||i.orderRef!==r.orderRef)this.fail(Error(`\u59D4\u6258 ${n} \u7684\u4F1A\u8BDD\u8EAB\u4EFD\u53D1\u751F\u53D8\u5316`))}).catch((i)=>{if(this._phase==="closed")return;let o=i instanceof Error?i.message:String(i);if(this.beginRecovery(),i instanceof Qe)this.emitError({vtOrderId:n,orderRef:r.orderRef,instrumentID:r.instrumentID,operation:"submit",message:o});else{let s=this.orders.get(n);if(s&&U(s)){let a={...s,statusMessage:`\u62A5\u5355\u7ED3\u679C\u5F85\u786E\u8BA4: ${o}`};this.orders.set(n,a),this.emitOrder(a)}}this.reconcileAfterRequestFailure()}),{vtOrderId:n,orderRef:r.orderRef}}cancelOrder(e){this.ensureReady();let t=this.orders.get(e);if(!t)throw Error(`\u627E\u4E0D\u5230\u5B9E\u76D8\u59D4\u6258: ${e}`);if(!U(t))throw Error(`\u59D4\u6258\u5DF2\u7EC8\u7ED3\uFF0C\u4E0D\u80FD\u64A4\u5355: ${e}`);this.pendingCancels.add(e),this.api.cancelOrder({orderRef:t.identity.orderRef,frontID:t.identity.frontID,sessionID:t.identity.sessionID,exchangeID:t.identity.exchangeID,instrumentID:t.identity.instrumentID}).catch((r)=>{if(this._phase==="closed")return;this.emitError({vtOrderId:e,orderRef:t.identity.orderRef,instrumentID:t.instrumentID,operation:"cancel",message:r instanceof Error?r.message:String(r)}),this.reconcileAfterRequestFailure()})}onOrder(e){return this.orderHandlers.add(e),()=>this.orderHandlers.delete(e)}onTrade(e){return this.tradeHandlers.add(e),()=>this.tradeHandlers.delete(e)}onOrderError(e){return this.errorHandlers.add(e),()=>this.errorHandlers.delete(e)}onPhase(e){return this.phaseHandlers.add(e),()=>this.phaseHandlers.delete(e)}onReconciled(e){return this.reconcileHandlers.add(e),()=>this.reconcileHandlers.delete(e)}onFault(e){return this.faultHandlers.add(e),()=>this.faultHandlers.delete(e)}close(){if(this._phase==="closed")return;this.setPhase("closed");for(let e of this.cleanups.splice(0))e();this.pendingEvents.length=0,this.unresolvedTrades.length=0,this.orderHandlers.clear(),this.tradeHandlers.clear(),this.errorHandlers.clear(),this.phaseHandlers.clear(),this.reconcileHandlers.clear(),this.faultHandlers.clear()}beginRecovery(){if(this._phase==="closed"||this._phase==="faulted")return;this.setPhase("recovering")}reconcileAfterRequestFailure(){if(this.beginRecovery(),this.api.connected)this.reconcile(!0).catch((e)=>this.fail(e))}async reconcile(e){if(this.recoveryTask)return this.recoveryTask;let t=this.performReconcile(e);this.recoveryTask=t;try{return await t}finally{if(this.recoveryTask===t)this.recoveryTask=null,this.recoveryObservedOrderIds=null}}async performReconcile(e){let t=this.requireSession();this.recoveryObservedOrderIds=new Set,this.setPhase("recovering");let r=await this.api.queryOrders({broker:this.options.broker,investorId:this.options.investorId}),n=new Map(this.orders);this.orderIdBySys.clear(),this.orderIdByRef.clear(),this.ambiguousOrderRefs.clear();let i=r.map((m)=>(this.validateOwner(m,"\u59D4\u6258"),this.acceptOrder(xt(m),!1))),s=(await this.api.queryTrades({broker:this.options.broker,investorId:this.options.investorId})).map((m)=>(this.validateOwner(m,"\u6210\u4EA4"),this.normalizeTrade(m))),a=[];for(let m of s){if(this.seenTrades.has(m.vtTradeId))continue;a.push(m),this.rememberTrade(m)}let d=await this.api.queryPositions(this.options.broker,this.options.investorId),c=this.normalizePositions(d),u=await this.api.queryAccount(this.options.broker,this.options.investorId);if(this.validateAccounts(u,t.tradingDay),this._phase==="closed"||this._phase==="faulted")throw Error(`CTP \u6062\u590D\u5DF2\u7EC8\u6B62\uFF08${this._phase}\uFF09`);let l={reason:e?"reconnect":"initial",tradingDay:_(t.tradingDay,"\u767B\u5F55 TradingDay"),accounts:u,positions:c,orders:i,trades:s,recoveredAt:(this.options.now??Date.now)()};if(this.currentSnapshot=l,e){for(let m of i){let v=n.get(m.vtOrderId);if(!v||this.orderFingerprint(v)!==this.orderFingerprint(m))this.emitOrder(m)}for(let m of a)this.emitTrade(m)}let f=this.pendingEvents.splice(0);for(let m of f)this.process(m);if(this.flushUnresolvedTrades(),this.unresolvedTrades.length>0)throw Error(`${this.unresolvedTrades.length} \u7B14\u6210\u4EA4\u65E0\u6CD5\u5173\u8054\u59D4\u6258`);let h=this.recoveryObservedOrderIds;for(let[m,v]of n)if(v.identity.tradingDay===l.tradingDay&&U(v)&&this.orders.has(m)&&!h.has(m))throw Error(`\u6D3B\u52A8\u59D4\u6258\u672A\u51FA\u73B0\u5728\u6062\u590D\u5FEB\u7167: ${m}`);l.orders=[...h].map((m)=>this.orders.get(m)).filter((m)=>m!==void 0&&m.identity.tradingDay===l.tradingDay);for(let m of this.reconcileHandlers)m(l);return this.setPhase("ready"),l}receive(e){if(this._phase==="closed"||this._phase==="faulted")return;if(this._phase!=="ready"){if(this.pendingEvents.length>=Br){this.fail(Error("CTP \u6062\u590D\u671F\u95F4\u4E8B\u4EF6\u7F13\u5B58\u6EA2\u51FA"));return}this.pendingEvents.push(e);return}try{this.process(e)}catch(t){this.fail(t)}}process(e){if(e.kind==="order")this.validateOwner(e.value,"\u59D4\u6258"),this.acceptOrder(xt(e.value),!0),this.flushUnresolvedTrades();else if(e.kind==="trade")this.validateOwner(e.value,"\u6210\u4EA4"),this.processTrade(e.value,!0);else this.processError(e.value)}acceptOrder(e,t){let r=this.orders.get(e.vtOrderId),n=e;if(r){if(r.instrumentID!==e.instrumentID||r.exchangeID!==e.exchangeID||r.side!==e.side||r.offset!==e.offset||r.volume!==e.volume)throw Error(`\u59D4\u6258\u8EAB\u4EFD\u5B57\u6BB5\u53D1\u751F\u53D8\u5316: ${e.vtOrderId}`);if(r.orderSysID&&e.orderSysID&&r.orderSysID!==e.orderSysID)throw Error(`\u59D4\u6258 OrderSysID \u53D1\u751F\u53D8\u5316: ${e.vtOrderId}`);if(e.traded<r.traded||this.orderStage(e)<this.orderStage(r))n=r;else n={...e,orderSysID:e.orderSysID||r.orderSysID,...e.traceId||!r.traceId?{}:{traceId:r.traceId}}}if(this.orders.set(n.vtOrderId,n),this.recoveryObservedOrderIds?.add(n.vtOrderId),this.bindOrderRef(n.identity.tradingDay,n.identity.orderRef,n.vtOrderId),n.orderSysID)this.orderIdBySys.set(Lr(n.exchangeID,n.orderSysID),n.vtOrderId);if(!U(n))this.pendingCancels.delete(n.vtOrderId);if(t&&(!r||this.orderFingerprint(r)!==this.orderFingerprint(n)))this.emitOrder(n);return n}normalizeTrade(e){return Ti(e,(t,r,n,i)=>this.orderIdBySys.get(Lr(t,r))??this.orderIdByRef.get(Hr(n,i))??null,this.session?.tradingDay)}bindOrderRef(e,t,r){let n=Hr(e,t);if(this.ambiguousOrderRefs.has(n))return;let i=this.orderIdByRef.get(n);if(i&&i!==r){this.orderIdByRef.delete(n),this.ambiguousOrderRefs.add(n);return}this.orderIdByRef.set(n,r)}normalizePositions(e){let t=_(this.requireSession().tradingDay,"\u767B\u5F55 TradingDay");for(let r of e)if(this.validateOwner(r,"\u6301\u4ED3"),_(r.tradingDay,`\u6301\u4ED3 ${r.instrumentID} TradingDay`)!==t)throw Error(`\u6301\u4ED3 TradingDay \u4E0E\u767B\u5F55\u4F1A\u8BDD\u4E0D\u4E00\u81F4: ${r.tradingDay}/${t}`);return Ei(e,this.contracts)}validateOwner(e,t){let r=b(e.brokerID,`${t} BrokerID`),n=b(e.investorID,`${t} InvestorID`);if(r!==this.options.broker||n!==this.options.investorId)throw Error(`${t}\u8D26\u6237\u8EAB\u4EFD\u4E0D\u5339\u914D: ${r}/${n}`)}validateAccounts(e,t){let r=_(t,"\u767B\u5F55 TradingDay");if(e.length===0)throw Error("\u8D26\u6237\u67E5\u8BE2\u8FD4\u56DE\u7A7A\u7ED3\u679C");for(let n of e){let i=b(n.brokerID,"\u8D26\u6237 BrokerID");if(b(n.accountID,"\u8D26\u6237 AccountID"),i!==this.options.broker)throw Error(`\u8D26\u6237 BrokerID \u4E0D\u5339\u914D: ${i}`);if(_(n.tradingDay,"\u8D26\u6237 TradingDay")!==r)throw Error(`\u8D26\u6237 TradingDay \u4E0E\u767B\u5F55\u4F1A\u8BDD\u4E0D\u4E00\u81F4: ${n.tradingDay}/${r}`);for(let[o,s]of Object.entries({preBalance:n.preBalance,balance:n.balance,available:n.available,currMargin:n.currMargin,frozenMargin:n.frozenMargin,frozenCash:n.frozenCash,frozenCommission:n.frozenCommission,closeProfit:n.closeProfit,positionProfit:n.positionProfit,commission:n.commission,deposit:n.deposit,withdraw:n.withdraw}))Ze(s,`\u8D26\u6237 ${o}`)}}processTrade(e,t){let r;try{r=this.normalizeTrade(e)}catch(n){if(n instanceof Ct){if(this.unresolvedTrades.length>=Br)throw Error("\u65E0\u6CD5\u5173\u8054\u7684\u6210\u4EA4\u7F13\u5B58\u6EA2\u51FA");this.unresolvedTrades.push(e);return}throw n}if(this.seenTrades.has(r.vtTradeId))return;if(this.rememberTrade(r),t)this.emitTrade(r)}flushUnresolvedTrades(){if(this.unresolvedTrades.length===0)return;let e=this.unresolvedTrades.splice(0);for(let t of e)this.processTrade(t,!0)}processError(e){let t=this.requireSession(),r=b(e.orderRef,"\u9519\u8BEF\u56DE\u62A5 OrderRef"),n=_t({...t,orderRef:r}),i=this.pendingCancels.has(n)?"cancel":"submit";this.emitError({vtOrderId:n,orderRef:r,...e.instrumentID?{instrumentID:e.instrumentID.toUpperCase()}:{},operation:i,message:e.errorMsg})}rememberTrade(e){if(!this.tradeLedgerDay||e.tradingDay>this.tradeLedgerDay){if(this.tradeLedgerDay)this.seenTrades.clear();this.tradeLedgerDay=e.tradingDay}this.seenTrades.add(e.vtTradeId)}orderFingerprint(e){return`${e.status}|${e.traded}|${e.orderSysID}|${e.statusMessage}`}orderStage(e){switch(e.status){case"submitting":return 0;case"notTraded":return 1;case"partTraded":return 2;case"allTraded":case"cancelled":case"rejected":return 3}}ensureReady(){if(this._phase!=="ready")throw Error(`CTP \u4EA4\u6613\u9002\u914D\u5668\u672A\u5C31\u7EEA\uFF08${this._phase}\uFF09`)}requireSession(){if(!this.session)throw Error("CTP \u4EA4\u6613\u4F1A\u8BDD\u4E0D\u53EF\u7528");return this.session}setSession(e){_(e.tradingDay,"\u767B\u5F55 TradingDay"),N(e.frontID,"\u767B\u5F55 FrontID"),Xe(e.sessionID,"\u767B\u5F55 SessionID"),this.session=e}setPhase(e){if(this._phase===e)return;if(this._phase==="closed")return;if(this._phase==="faulted"&&e!=="closed")return;this._phase=e;for(let t of this.phaseHandlers)t(e)}fail(e){if(this._phase==="closed"||this._phase==="faulted")return;let t=e instanceof Error?e.message:String(e);this.setPhase("faulted");for(let r of this.faultHandlers)r(t)}emitOrder(e){for(let t of this.orderHandlers)t(e)}emitTrade(e){for(let t of this.tradeHandlers)t(e)}emitError(e){this.pendingCancels.delete(e.vtOrderId);let t=this.orders.get(e.vtOrderId);if(t&&U(t)){let r=e.operation==="submit"?{...t,status:"rejected",statusMessage:e.message}:{...t,statusMessage:`\u64A4\u5355\u5931\u8D25: ${e.message}`};this.orders.set(e.vtOrderId,r),this.emitOrder(r)}for(let r of this.errorHandlers)r(e)}}var At={queryOrder:{event:"onQueryOrderResult",field:"orders"},queryTrade:{event:"onQueryTradeResult",field:"trades"},queryPosition:{event:"onQueryPositionResult",field:"positions"},queryAccount:{event:"onQueryAccountResult",field:"accounts"}};class Vr{session;clock;trace;requests=[];pending=new Map;handlers=new Map;exits=new Set;held=new Set;waiters=new Set;state;constructor(e,t,r,n={}){this.session=e;this.clock=t;this.trace=r;this.state=structuredClone(n)}request(e,t,r=30000){let n={id:this.requests.length+1,method:e,params:structuredClone(t),now:this.clock.now};return this.requests.push(n),this.trace.record("broker",{operation:"rpc",request:n}),new Promise((i,o)=>{let s=this.clock.schedule(()=>{this.pending.delete(n.id),o(Error(`Test gateway ${e} request timed out`))},r);this.pending.set(n.id,{request:n,resolve:i,reject:o,cancelTimeout:s});for(let a of this.waiters)if(a.method===e)this.waiters.delete(a),a.resolve(structuredClone(n));if(!this.held.has(e))this.complete(n.id)})}pendingRequests(){return[...this.pending.values()].map((e)=>structuredClone(e.request))}waitForRequest(e){let t=this.pendingRequests().find((r)=>r.method===e);return t?Promise.resolve(t):new Promise((r,n)=>this.waiters.add({method:e,resolve:r,reject:n}))}setSnapshot(e){this.state={...this.state,...structuredClone(e)}}hold(e){this.held.add(e)}resume(e){this.held.delete(e);for(let{request:t}of[...this.pending.values()])if(t.method===e)this.complete(t.id)}reply(e,t){let r=this.pending.get(e);if(!r)throw Error(`Pending RPC does not exist: ${e}`);this.pending.delete(e),r.cancelTimeout();let n=r.request.method==="insertOrder"?{...this.session,orderRef:r.request.params.orderRef,requestID:e}:{requestID:e},i={id:e,...t??{ok:!0,data:n}};this.trace.record("broker",{operation:"rpcReply",response:i}),r.resolve(i)}completeQuery(e,t){let r=this.requests.find((o)=>o.id===e);if(!r||!Object.hasOwn(At,r.method))throw Error(`Query RPC does not exist: ${e}`);let n=At[r.method];if(this.pending.has(e))this.reply(e);let i=n.field==="accounts"?[{brokerID:"test",accountID:"test",tradingDay:this.session.tradingDay,preBalance:1e6,balance:1e6,available:1e6,currMargin:0,frozenMargin:0,frozenCash:0,frozenCommission:0,closeProfit:0,positionProfit:0,commission:0,deposit:0,withdraw:0}]:[];this.push(n.event,{requestID:e,[n.field]:structuredClone(t??this.state[n.field]??i)})}push(e,t){let r={method:e,params:structuredClone(t)};this.trace.record("broker",{operation:"push",message:r});for(let n of this.handlers.get(e)??[])n(structuredClone(r))}on(e,t){let r=this.handlers.get(e)??new Set;return r.add(t),this.handlers.set(e,r),()=>this.off(e,t)}off(e,t){this.handlers.get(e)?.delete(t)}onExit(e){return this.exits.add(e),()=>this.exits.delete(e)}resetClient(){let e=Error("Test gateway client closed");for(let t of this.pending.values())t.cancelTimeout(),t.reject(e);for(let t of this.waiters)t.reject(e);this.pending.clear(),this.waiters.clear(),this.held.clear()}complete(e){let t=this.pending.get(e).request;if(Object.hasOwn(At,t.method))this.completeQuery(e);else this.reply(e)}}class xe{clock;trace;observations;gateway;fixture;transport;instrument;api;adapter;orderRef;orders=new Set;trades=new Set;errors=new Set;reconciled=new Set;faults=new Set;constructor(e,t,r,n,i){this.clock=t;this.trace=r;this.observations=i;this.fixture=e,this.instrument=Ye(e);let o={tradingDay:e.tradingDay,frontID:1,sessionID:1,...n.gatewaySession};this.orderRef=BigInt(o.maxOrderRef??"0"),this.transport=new Vr(o,t,r,n.gatewayState);let s=this;this.gateway={get requests(){return structuredClone(s.transport.requests)},pendingRequests:()=>this.transport.pendingRequests(),waitForRequest:(a)=>this.transport.waitForRequest(a),setSnapshot:(a)=>this.transport.setSnapshot(a),hold:(a)=>this.transport.hold(a),resume:(a)=>this.transport.resume(a),reply:(a,d)=>this.transport.reply(a,d),completeQuery:(a,d)=>this.transport.completeQuery(a,d),push:(a,d)=>this.transport.push(a,d),disconnect:()=>this.transport.push("onDisconnected",{}),reconnect:(a)=>this.reconnect(a),queryOrders:()=>this.requireAdapter().queryOrders()}}get phase(){if(this.adapter?.phase==="ready")return"running";return this.adapter?.phase==="faulted"||this.adapter?.phase==="closed"?"faulted":"recovering"}async connect(){if(this.adapter)this.close();this.api=new Rt(this.transport,{clock:{now:()=>this.clock.now,schedule:this.clock.schedule}}),this.api.loginResult=this.transport.session,this.api.connected=!0,this.adapter=new Mt(this.api,{broker:"test",investorId:"test",now:()=>this.clock.now}),this.adapter.registerInstrument(this.instrument),this.adapter.onOrder((e)=>{for(let t of this.orders)t(e)}),this.adapter.onTrade((e)=>{for(let t of this.trades)t(e)}),this.adapter.onOrderError((e)=>{for(let t of this.errors)t(e)}),this.adapter.onReconciled((e)=>{for(let t of this.reconciled)t(e)}),this.adapter.onFault((e)=>{for(let t of this.faults)t(e)}),await this.adapter.initialize(this.transport.session)}close(){this.adapter?.close(),this.api?.dispose(),this.transport.resetClient()}async prepareInstrument(e,t){if(e!==this.instrument.instrumentID||t!==this.instrument.exchangeID)throw Error("Test instrument mismatch");return this.instrument}async prepareCommission(e,t){if(e!==this.instrument.instrumentID||t!==this.instrument.exchangeID)throw Error("Test commission mismatch")}getInstrument(e){return e===this.instrument.instrumentID?this.instrument:null}getCommission(e,t){if(e!==this.instrument.instrumentID||t!==this.instrument.exchangeID)return null;return Ge(this.fixture)}async queryPositions(e){if(this.phase!=="running")return{phase:this.phase,positions:[]};let t=await this.requireAdapter().queryPositions(e);return{phase:this.phase,positions:t}}queryOrders(e){return this.requireAdapter().queryOrders(e)}submitOrder(e){let t=String(++this.orderRef);if(t.length>12)throw Error("CTP OrderRef \u5DF2\u8017\u5C3D\uFF0C\u8BF7\u91CD\u542F\u4EA4\u6613\u4F1A\u8BDD");let r=this.requireAdapter().submitOrder({instrumentID:e.instrumentID,direction:e.direction,offsetFlag:e.offsetFlag,price:e.price,volume:e.volume,exchangeID:this.instrument.exchangeID,orderRef:t,traceId:`vibek:${e.strategyId}:${t}`}),n={vtOrderId:r.vtOrderId,direction:e.direction==="buy"?"long":"short",offset:e.offsetFlag,price:e.price,volume:e.volume};return this.observations.submissions.push(n),this.trace.record("submission",n),r}cancelOrder(e){this.observations.cancelRequests.push(e),this.trace.record("cancel",{vtOrderId:e}),this.requireAdapter().cancelOrder(e)}onOrder(e){return this.orders.add(e),()=>this.orders.delete(e)}onTrade(e){return this.trades.add(e),()=>this.trades.delete(e)}onOrderError(e){return this.errors.add(e),()=>this.errors.delete(e)}onReconciled(e){return this.reconciled.add(e),()=>this.reconciled.delete(e)}onFault(e){return this.faults.add(e),()=>this.faults.delete(e)}reconnect(e={}){let t=this.requireAdapter();return Object.assign(this.transport.session,e),new Promise((r,n)=>{let i=t.onPhase((o)=>{if(o==="ready")i(),r();else if(o==="faulted"||o==="closed")i(),n(Error(`CTP reconciliation ${o}`))});this.transport.push("onDisconnected",{}),this.transport.push("onReconnected",{...this.transport.session})})}requireAdapter(){if(!this.adapter)throw Error("CTP test adapter is not initialized");return this.adapter}}class Bt{fixture;history;now;generate;constructor(e,t,r,n){this.fixture=e;this.history=t;this.now=r;this.generate=n}async getBars(e,t){if(this.history.length===0&&this.generate)this.history.push(...Ii(e,t,this.fixture,this.now));Ie(this.history,this.now,e);let r=ke(this.history,t.timeframe,t.count);if(r.selectedCount!==t.count)throw Error(`\u6D4B\u8BD5\u9884\u70ED\u6570\u636E\u4E0D\u8DB3\uFF1A\u9700\u8981 ${t.count} \u6839 ${t.timeframe}\uFF0C\u4EC5\u6709 ${r.availableCount} \u6839`);return r.bars.map((n)=>({...n}))}destroy(){}}function Ii(e,t,r,n){if(t.count>1e5)throw Error(`\u6D4B\u8BD5\u9884\u70ED\u6570\u636E\u8BF7\u6C42\u8FC7\u5927: ${t.count}`);if(t.timeframe==="1d"){let d=Math.floor(n/60000)*60;return Array.from({length:t.count},(c,u)=>{let l=d-(t.count-u)*86400;return H(r,{code:e,close:r.seedPrice+u*r.priceTick,barTime:l,tradingDay:Ot(l*1000),boundaryReason:"sessionEnd"},u)})}let i=se[t.timeframe]/60,o=t.count*i;if(o>1e5)throw Error(`\u6D4B\u8BD5\u9884\u70ED\u6570\u636E\u8BF7\u6C42\u8FC7\u5927: ${o} \u6839 1min Bar`);let a=Math.floor(n/(i*60000))*i*60-o*60;return Array.from({length:o},(d,c)=>H(r,{code:e,close:r.seedPrice+c*r.priceTick,barTime:a+c*60,tradingDay:Tt(a+c*60)},c))}import{mkdtempSync as zo,rmSync as Uo}from"fs";import{tmpdir as jo}from"os";import{join as Go}from"path";class Ht{now;tasks=new Map;sequence=0;constructor(e){this.now=e}schedule=(e,t)=>{if(!Number.isSafeInteger(t)||t<0||!Number.isSafeInteger(this.now+t))throw Error("Scheduled delay must be a nonnegative safe integer");let r=++this.sequence;return this.tasks.set(r,{at:this.now+t,callback:e}),()=>{this.tasks.delete(r)}};advanceTo(e,t){if(!Number.isSafeInteger(e)||e<this.now)throw Error("\u6D4B\u8BD5\u65F6\u95F4\u4E0D\u80FD\u56DE\u9000\u6216\u8D85\u8FC7\u5B89\u5168\u6574\u6570\u8303\u56F4");let r=(Math.floor(this.now/1000)+1)*1000,n=0;while(!0){let i=1/0;for(let s of this.tasks.values())i=Math.min(i,s.at);let o=Math.min(i,t?r:1/0);if(o>e)break;if(this.now=o,t&&o===r)t(),r+=1000;for(let[s,a]of this.tasks)if(a.at<=this.now){if(this.tasks.delete(s),++n>1e5)throw Error("Test scheduler exceeded 100000 callbacks in one advance");a.callback()}}this.now=e}}import{AsyncLocalStorage as Di}from"async_hooks";class Lt{now;entries=[];context=new Di;constructor(e){this.now=e}get events(){return this.entries.slice()}close(){this.context.disable()}record(e,t){let r=this.entries.length+1;return this.entries.push(zr({sequence:r,now:this.now(),cause:this.context.getStore()??null,type:e,value:structuredClone(t)})),r}input(e,t){let r=this.record("input",e);return this.context.run(r,()=>{let n=t();if(n instanceof Promise)return n.then((i)=>(this.record("completion",{input:r,status:"fulfilled"}),i),(i)=>{throw this.record("completion",{input:r,status:"rejected",error:i instanceof Error?i.message:String(i)}),i});return n})}bind(e){let t=this.context.getStore()??null;return()=>this.context.run(t,e)}}function zr(e,t=new Set){if(e&&typeof e==="object"){if(t.has(e))return e;t.add(e);for(let r of Object.values(e))zr(r,t);Object.freeze(e)}return e}import{existsSync as ln}from"fs";import{join as I}from"path";import{existsSync as _i,mkdirSync as ya,readFileSync as Ci,renameSync as ba,unlinkSync as wa,writeFileSync as Sa}from"fs";import{homedir as Ce}from"os";import{dirname as Pi,isAbsolute as $i,join as C,resolve as zt}from"path";import{isIP as Oi}from"net";function Nt(e){if(e.trim()==="")return[];let t=[],r=new Set,n=e.split(",").map((i)=>i.trim()).filter(Boolean);for(let[i,o]of n.entries()){let s=o.indexOf("@");if(s<=0||s!==o.lastIndexOf("@"))throw Error(`ctp.front_candidates \u7B2C ${i+1} \u9879\u683C\u5F0F\u9519\u8BEF\uFF0C\u5E94\u4E3A \u63CF\u8FF0@IP`);let a=o.slice(0,s).trim(),d=o.slice(s+1).trim();if(a==="")throw Error(`ctp.front_candidates \u7B2C ${i+1} \u9879\u7F3A\u5C11\u7EBF\u8DEF\u63CF\u8FF0`);if(Oi(d)===0)throw Error(`ctp.front_candidates \u7B2C ${i+1} \u9879\u4E0D\u662F\u6709\u6548 IP: ${d||"(\u7A7A)"}`);if(r.has(d))throw Error(`ctp.front_candidates \u5305\u542B\u91CD\u590D IP: ${d}`);r.add(d),t.push({description:a,ip:d})}return t}var _e=[{start:"09:00:00",end:"10:15:00",boundaryReason:"break",acceptsPreOpenTick:!0},{start:"10:30:00",end:"11:30:00",boundaryReason:"break"},{start:"13:30:00",end:"15:00:00",boundaryReason:"sessionEnd"}],Ri=[{start:"09:30:00",end:"11:30:00",boundaryReason:"break",acceptsPreOpenTick:!0},{start:"13:00:00",end:"15:00:00",boundaryReason:"sessionEnd"}],xi=[{start:"09:30:00",end:"11:30:00",boundaryReason:"break",acceptsPreOpenTick:!0},{start:"13:00:00",end:"15:15:00",boundaryReason:"sessionEnd"}];function Ft(e){return[{start:"21:00:00",end:e,boundaryReason:"break",acceptsPreOpenTick:!0},..._e]}var et=Ft("23:00:00"),Ur=Ft("01:00:00"),jr=Ft("02:30:00"),qt=new Map;function D(e,t,r){for(let n of t){let i=n.toUpperCase();qt.set(`${e}.${i}`,{exchangeID:e,productID:i,segments:r})}}D("CFFEX",["IF","IH","IC","IM"],Ri);D("CFFEX",["T","TF","TS","TL"],xi);D("SHFE",["AU","AG"],jr);D("SHFE",["CU","AL","ZN","PB","NI","SN","SS","AO","AD"],Ur);D("SHFE",["RB","WR","HC","RU","BU","FU","SP","BR"],et);D("INE",["SC"],jr);D("INE",["BC"],Ur);D("INE",["NR","LU"],et);D("INE",["EC"],_e);D("DCE",["A","B","C","CS","M","Y","P","L","L_F","V","V_F","PP","PP_F","J","JM","I","EG","EB","PG"],et);D("DCE",["JD","FB","BB","RR","LH","LG","BZ"],_e);D("CZCE",["CF","SR","TA","OI","MA","FG","RM","ZC","CY","SA","PF","PX","SH","PR"],et);D("CZCE",["WH","PM","RI","RS","JR","LR","SF","SM","AP","CJ","UR","PK"],_e);D("GFEX",["SI","LC","PS","PT","PD"],_e);function Gr(e,t){return qt.get(`${e.toUpperCase()}.${t.toUpperCase()}`)??null}function tt(e,t){let r=Gr(e,t);if(!r)throw Error(`\u4EA7\u54C1\u65F6\u6BB5\u76EE\u5F55\u4E0D\u5305\u542B ${t.toUpperCase()}.${e.toUpperCase()}`);return r}function Vt(){return[...qt.values()]}var Mi="VIBEK_CONFIG_PATH",Ai="VIBEK_PROCESS_ACCOUNT",Ut=/^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$/,Kr=["trace","debug","info","warn","error"],Yr=["realtime","replay"];class ee extends Error{path;diagnostics;constructor(e,t){super(`\u914D\u7F6E\u6587\u4EF6\u65E0\u6548: ${e}
2
+ var wt=import.meta.require;function w(e){return e.status==="submitting"||e.status==="notTraded"||e.status==="partTraded"}var br=Symbol.for("vibek.strategy.cta-template-runtime");function St(e){if(!e||typeof e!=="object")return null;let t=e[br];if(typeof t!=="function")return null;let r=t.call(e);if(!r||typeof r.bindContext!=="function"||typeof r.restoreVariables!=="function"||typeof r.setRuntimeState!=="function"||typeof r.getStateVariables!=="function")return null;return r}var we=/^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$/;var kr=["strategyName","vtSymbol","mode","inited","trading","pos"],Xn=new Set([...kr,"constructor","__proto__","prototype","onInit","onStart","onStop","onTick","onBar","onTrade","onOrder","buy","sell","short","cover","cancelOrder","cancelAll","loadBars","registerEvent","claimOrder","writeLog","emitHook","getCurrentTime","getContract","getCommission","getPriceTick","getSize"]);function Se(e,t,r){if(!Sr(e))throw Error("\u7B56\u7565 default export \u5FC5\u987B\u662F\u5BF9\u8C61");let n=Object.keys(e).find((p)=>p!=="strategy");if(n)throw Error(`\u7B56\u7565\u5B9A\u4E49\u4E0D\u652F\u6301\u5B57\u6BB5 "${n}"\uFF1Bid\u3001vtSymbol \u548C setting \u5FC5\u987B\u5728\u52A0\u8F7D\u65F6\u4F20\u5165`);if(typeof e.strategy!=="function")throw Error(`\u7B56\u7565 ${t} \u7684 strategy \u5FC5\u987B\u662F\u7C7B`);if(!Sr(r))throw Error(`\u7B56\u7565 ${t} \u7684 setting \u5FC5\u987B\u662F\u5BF9\u8C61`);let i=e.strategy,o=wr(i.parameters,"parameters",t),s=wr(i.variables,"variables",t),a=[...o,...s].find((p)=>Xn.has(p));if(a)throw Error(`\u7B56\u7565 ${t} \u7684 parameters/variables \u4E0D\u5E94\u58F0\u660E\u6846\u67B6\u5B57\u6BB5 ${a}`);let d=o.find((p)=>s.includes(p));if(d)throw Error(`\u7B56\u7565 ${t} \u7684\u5B57\u6BB5 ${d} \u4E0D\u80FD\u540C\u65F6\u5C5E\u4E8E parameters \u548C variables`);let c=Object.keys(r).find((p)=>!o.includes(p));if(c)throw Error(`\u7B56\u7565 ${t} \u4E0D\u652F\u6301\u53C2\u6570 "${c}"`);let u;try{u=new i}catch(p){throw Error(`\u7B56\u7565 ${t} \u6784\u9020\u5931\u8D25: ${p instanceof Error?p.message:String(p)}`)}let l=St(u);if(!l||typeof u.onInit!=="function")throw Error(`\u7B56\u7565 ${t} \u5FC5\u987B\u7EE7\u627F CtaTemplate \u5E76\u5B9E\u73B0 onInit()`);for(let p of kr)if(Object.hasOwn(u,p))throw Error(`\u7B56\u7565 ${t} \u4E0D\u5F97\u58F0\u660E\u6846\u67B6\u5B57\u6BB5 ${p}`);for(let p of[...o,...s])if(!(p in u))throw Error(`\u7B56\u7565 ${t} \u58F0\u660E\u4E86\u5B57\u6BB5 ${p}\uFF0C\u4F46\u5B9E\u4F8B\u6CA1\u6709\u5BF9\u5E94\u9ED8\u8BA4\u503C`);let f=o.map((p)=>{let k=Tr(ti(u,p),`\u7B56\u7565 ${t} \u53C2\u6570 ${p} \u9ED8\u8BA4\u503C`);return{name:p,defaultValue:k,kind:ei(k)}}),h=vr(r,`\u7B56\u7565 ${t} setting`),m=Object.fromEntries(f.map((p)=>[p.name,Object.hasOwn(h,p.name)?h[p.name]:p.defaultValue]));return{definition:{strategy:i},ctor:i,instance:u,runtime:l,effectiveSetting:vr(m,`\u7B56\u7565 ${t} \u751F\u6548 setting`),inspection:{name:i.name,author:i.author??"",parameters:f}}}function wr(e,t,r){if(e===void 0)return[];if(!Array.isArray(e))throw Error(`\u7B56\u7565 ${r} \u7684 ${t} \u5FC5\u987B\u662F\u5B57\u7B26\u4E32\u6570\u7EC4`);let n=e.map((i,o)=>{if(typeof i!=="string"||!/^[A-Za-z_$][A-Za-z0-9_$]*$/.test(i))throw Error(`\u7B56\u7565 ${r} \u7684 ${t}[${o}] \u975E\u6CD5`);return i});if(new Set(n).size!==n.length)throw Error(`\u7B56\u7565 ${r} \u7684 ${t} \u5B58\u5728\u91CD\u590D\u9879`);return n}function ei(e){if(typeof e==="number")return"number";if(typeof e==="boolean")return"boolean";if(typeof e==="string")return"string";return"json"}function ti(e,t){return e[t]}function Sr(e){return e!==null&&typeof e==="object"&&!Array.isArray(e)}function vr(e,t){return Tr(e,t)}function Tr(e,t){return vt(e,t,new Set),JSON.parse(JSON.stringify(e))}function vt(e,t,r){if(e===null||typeof e==="string"||typeof e==="boolean")return;if(typeof e==="number"){if(!Number.isFinite(e))throw Error(`${t} \u5305\u542B\u975E\u6709\u9650\u6570\u5B57`);return}if(typeof e!=="object")throw Error(`${t} \u5305\u542B\u4E0D\u53EF\u5E8F\u5217\u5316\u7684 ${typeof e}`);if(r.has(e))throw Error(`${t} \u5305\u542B\u5FAA\u73AF\u5F15\u7528`);if(r.add(e),Array.isArray(e))for(let n=0;n<e.length;n++)vt(e[n],`${t}[${n}]`,r);else{let n=Object.getPrototypeOf(e);if(n!==Object.prototype&&n!==null)throw Error(`${t} \u5FC5\u987B\u662F\u666E\u901A\u5BF9\u8C61\u6216\u6570\u7EC4`);for(let[i,o]of Object.entries(e))vt(o,`${t}.${i}`,r)}r.delete(e)}class Ve{timeframes;currentBars=new Map;completedBars=[];tickCallbacks=[];barCallbacks=[];lastTickTime=0;lastCumVolume=null;lastTradingDay="";constructor(e){this.timeframes=e.timeframes.map((t)=>({label:t,seconds:Ir(t)}))}onTick(e){this.tickCallbacks.push(e)}offTick(e){let t=this.tickCallbacks.indexOf(e);if(t>=0)this.tickCallbacks.splice(t,1)}onBar(e){this.barCallbacks.push(e)}offBar(e){let t=this.barCallbacks.indexOf(e);if(t>=0)this.barCallbacks.splice(t,1)}pushTick(e){let t=ni(e);if(this.lastTickTime>0&&t<this.lastTickTime)throw Error(`tick \u65F6\u95F4\u56DE\u9000: ${e.code} ${t} < ${this.lastTickTime}`);this.lastTickTime=t;let r=Boolean(e.tradingDay&&this.lastTradingDay&&e.tradingDay!==this.lastTradingDay),n=0;if(!r&&this.lastCumVolume!==null&&e.volume>=this.lastCumVolume)n=e.volume-this.lastCumVolume;if(this.lastCumVolume=e.volume,e.tradingDay)this.lastTradingDay=e.tradingDay;for(let i of this.tickCallbacks)i(e);for(let i of this.timeframes)this.updateBar(i,e,t,n)}completeThrough(e){let t=Math.floor(e/1000);for(let r of this.timeframes){let n=this.currentBars.get(r.label);if(n&&n.barTime+r.seconds<=t)this.finalizeBar(r.label)}}getCompletedBars(){return this.completedBars}getCurrentBar(e){return this.currentBars.get(e)??null}forceCompleteAll(e){for(let t of this.timeframes)this.finalizeBar(t.label,e)}forceComplete(e,t){if(this.timeframes.some((r)=>r.label===e))this.finalizeBar(e,t)}markDisconnected(){for(let e of this.currentBars.values())e.boundaryReason="disconnect";this.lastCumVolume=null}reset(){this.currentBars.clear(),this.completedBars=[],this.lastTickTime=0,this.lastCumVolume=null,this.lastTradingDay=""}clearCompletedBars(){this.completedBars=[]}_registrySize(){return this.currentBars.size}updateBar(e,t,r,n){let i=ri(r,e.seconds),o=t.lastPrice,s=this.currentBars.get(e.label);if(s&&s.barTime<i)this.finalizeBar(e.label),s=void 0;if(!s){this.currentBars.set(e.label,{code:t.code,timeframe:e.label,barTime:i,open:o,high:o,low:o,close:o,volume:n,tickCount:1,...t.tradingDay?{tradingDay:t.tradingDay}:{}});return}if(s.high=Math.max(s.high,o),s.low=Math.min(s.low,o),s.close=o,s.volume+=n,s.tickCount++,t.tradingDay)s.tradingDay=t.tradingDay}finalizeBar(e,t){let r=this.currentBars.get(e);if(!r)return;if(this.currentBars.delete(e),r.tickCount===0)return;let n=t??r.boundaryReason,i={code:r.code,timeframe:r.timeframe,barTime:r.barTime,open:r.open,high:r.high,low:r.low,close:r.close,volume:r.volume,...r.tradingDay?{tradingDay:r.tradingDay}:{},...n?{boundaryReason:n}:{}};if(this.completedBars.push(i),this.completedBars.length>1000)this.completedBars.shift();for(let o of this.barCallbacks)o(i)}}function Ir(e){let t=/^(\d+)(min|h|d)$/.exec(e);if(!t)throw Error(`\u4E0D\u652F\u6301\u7684 K \u7EBF\u5468\u671F: ${e}`);let r=Number(t[1]);if(!Number.isInteger(r)||r<=0)throw Error(`\u4E0D\u652F\u6301\u7684 K \u7EBF\u5468\u671F: ${e}`);if(t[2]==="min")return r*60;if(t[2]==="h")return r*3600;return r*86400}function ri(e,t){return Math.floor(e/t)*t}function ni(e){if(Number.isFinite(e.datetime))return Math.floor(e.datetime/1000);return Math.floor(Or(e.actionDay,e.updateTime,e.updateMillisec??0)/1000)}var Dr=28800000,kt=86400000;function ii(e){let r=((e+Dr)%kt+kt)%kt;return e-r}function oi(e){if(!e||!/^\d{8}$/.test(e))return null;let t=Number(e.slice(0,4)),r=Number(e.slice(4,6)),n=Number(e.slice(6,8)),i=new Date(Date.UTC(t,r-1,n));return i.getUTCFullYear()===t&&i.getUTCMonth()===r-1&&i.getUTCDate()===n?[t,r,n]:null}var Er=new Set,si=43200000;function Or(e,t,r){if(!t)return Date.now();let n=/^(\d{2}):(\d{2}):(\d{2})$/.exec(t);if(!n){let d=new Date(t).getTime();return Number.isNaN(d)?Date.now():d}let i=Number(n[1]),o=Number(n[2]),s=Number(n[3]);if(i>23||o>59||s>59||!Number.isInteger(r)||r<0||r>999)return Date.now();let a=oi(e);if(a){let d=Date.UTC(a[0],a[1]-1,a[2],i,o,s,r)-Dr,c=Math.abs(d-Date.now());if(c>si&&!Er.has(e))Er.add(e),console.warn(`[bar-aggregator] actionDay \u4E0E\u7CFB\u7EDF\u65E5\u671F\u504F\u5DEE ${Math.round(c/3600000)}h: ${e}`);return d}return ii(Date.now())+(i*3600+o*60+s)*1000+r}var qe=["1min","3min","5min","10min","15min","30min","1h","2h","4h","1d"],se={"1min":60,"3min":180,"5min":300,"10min":600,"15min":900,"30min":1800,"1h":3600,"2h":7200,"4h":14400,"1d":86400};var ve=qe.join("\u3001");var ai=/^(\d{4})(\d{2})(\d{2})$/;function Z(e){return typeof e==="string"&&qe.includes(e)}function ze(e,t,r){if(t!=="1d"){let n=se[t];return Math.floor(e/n)*n}return di(r??Tt(e))}function Tt(e){let t=new Date((e+28800)*1000);if(t.getUTCHours()>=20||t.getUTCDay()===0||t.getUTCDay()===6){t.setUTCDate(t.getUTCDate()+(t.getUTCHours()>=20?1:0));while(t.getUTCDay()===0||t.getUTCDay()===6)t.setUTCDate(t.getUTCDate()+1)}return`${t.getUTCFullYear()}${Rr(t.getUTCMonth()+1)}${Rr(t.getUTCDate())}`}function di(e){let t=ai.exec(e);if(!t)throw Error(`\u975E\u6CD5\u4EA4\u6613\u65E5: ${e}`);let r=Number(t[1]),n=Number(t[2]),i=Number(t[3]),o=Date.UTC(r,n-1,i),s=new Date(o);if(s.getUTCFullYear()!==r||s.getUTCMonth()!==n-1||s.getUTCDate()!==i)throw Error(`\u975E\u6CD5\u4EA4\u6613\u65E5: ${e}`);return Math.floor(o/1000)-28800}function _r(e,t){let r=e==="1d"?600:se[e]/60;return t*r+(r-1)}function Rr(e){return String(e).padStart(2,"0")}var ci=new Set(qe);class Ue{timeframe;seconds;current=null;constructor(e){this.timeframe=e;if(!ci.has(e))throw Error(`\u5468\u671F "${e}" \u4E0D\u53D7\u652F\u6301\uFF1B\u4EC5\u652F\u6301 ${ve}`);this.seconds=se[e]}pushBar(e){let t=this.pushBars(e);if(t.length>1)throw Error("\u5355\u6839 1min bar \u540C\u65F6\u95ED\u5408\u4E86\u591A\u4E2A\u7A97\u53E3\uFF1B\u8BF7\u4F7F\u7528 pushBars() \u4FDD\u7559\u5168\u90E8\u4FE1\u53F7");return t[0]??null}pushBars(e){if(e.timeframe!=="1min")throw Error(`BarGenerator \u53EA\u63A5\u53D7\u95ED\u5408 1min bar\uFF0C\u6536\u5230 ${e.timeframe}`);if(this.seconds===60)return[e];let t=[],r=ze(e.barTime,this.timeframe,e.tradingDay);if(this.current&&this.current.barTime!==r){let o=this.finish();if(o)t.push(o)}if(!this.current)this.start(e,r);else this.merge(e);let n=this.timeframe!=="1d"&&e.barTime+60>=r+this.seconds,i=this.seconds>=3600?e.boundaryReason==="sessionEnd":e.boundaryReason!==void 0;if(n||i){let o=this.finish(e.boundaryReason);if(o)t.push(o)}return t}flush(e){return this.finish(e)}start(e,t){this.current={code:e.code,timeframe:this.timeframe,barTime:t,open:e.open,high:e.high,low:e.low,close:e.close,volume:e.volume,...e.tradingDay?{tradingDay:e.tradingDay}:{}}}merge(e){let t=this.current;if(t.high=Math.max(t.high,e.high),t.low=Math.min(t.low,e.low),t.close=e.close,t.volume+=e.volume,e.tradingDay)t.tradingDay=e.tradingDay}finish(e){let t=this.current;if(!t)return null;return this.current=null,{...t,...e?{boundaryReason:e}:{}}}}function xr(e){if(e.timeframe!=="1min")throw Error(`\u7B56\u7565\u9884\u70ED\u53EA\u63A5\u53D7\u95ED\u5408 1min Bar\uFF0C\u6536\u5230 ${e.timeframe}`)}function*Cr(e,t){if(t==="1min"){for(let o=0;o<e.length;o++)xr(e[o]),yield{startIndex:o,endIndex:o,triggerIndex:o};return}let r=new Ue(t),n=0,i=-1/0;for(let o=0;o<e.length;o++){let s=e[o];if(xr(s),s.barTime<i)throw Error("\u7B56\u7565\u9884\u70ED Bar \u5FC5\u987B\u6309\u65F6\u95F4\u5347\u5E8F\u6392\u5217");i=s.barTime;let a=ze(s.barTime,t,s.tradingDay);for(let d of r.pushBars(s)){let c=d.barTime===a?o:o-1;if(c<n)throw Error("\u7B56\u7565\u9884\u70ED Bar \u805A\u5408\u8FB9\u754C\u65E0\u6548");yield{startIndex:n,endIndex:c,triggerIndex:o},n=c+1}}}function Et(e,t){let r=0;for(let n of Cr(e,t))r++;return r}function ke(e,t,r){if(!Number.isInteger(r)||r<=0)throw Error("\u9884\u70ED Bar count \u5FC5\u987B\u4E3A\u6B63\u6574\u6570");let n=[...Cr(e,t)],i=n.length;if(i<r)return{bars:[...e],availableCount:i,selectedCount:i};let o=n[i-r];return{bars:e.slice(o.startIndex),availableCount:i,selectedCount:r}}var ui=new Set(["CFFEX","SHFE","CZCE","DCE","INE","GFEX"]);function K(e){let t=e.trim(),[r="",n,...i]=t.split(".");if(!r||!n||i.length>0)throw Error(`vtSymbol \u975E\u6CD5: ${e}`);if(!/^[A-Za-z][A-Za-z0-9]*$/.test(r)||!/\d/.test(r))throw Error(`vtSymbol \u5408\u7EA6\u4EE3\u7801\u975E\u6CD5: ${e}`);if(!ui.has(n.toUpperCase()))throw Error(`vtSymbol \u4EA4\u6613\u6240\u975E\u6CD5: ${e}`);let o=r.toUpperCase();return{instrumentID:o,vtSymbol:`${o}.${n.toUpperCase()}`}}function Pr(e){let t=e.split(".")[1]?.toUpperCase();return t==="SHFE"||t==="INE"}var li="20260105",mi=3500;function Y(e){if(!ae(e))throw Error("\u6D4B\u8BD5\u5B9A\u4E49 fixture \u5FC5\u987B\u662F\u5BF9\u8C61");if(Te(e,["vtSymbol","setting","instrument","commission","seedPrice","tradingDay"],"fixture"),typeof e.vtSymbol!=="string")throw Error("fixture.vtSymbol \u5FC5\u987B\u662F\u5B57\u7B26\u4E32");let t=K(e.vtSymbol);if(!ae(e.instrument))throw Error("fixture.instrument \u5FC5\u987B\u662F\u5BF9\u8C61");Te(e.instrument,["priceTick","size","name","minOrderVolume","maxOrderVolume","longMarginRatio","shortMarginRatio","isTrading"],"fixture.instrument");let r=E(e.instrument.priceTick,"fixture.instrument.priceTick"),n=_(e.instrument.size,"fixture.instrument.size"),i=e.instrument.name===void 0?t.instrumentID:e.instrument.name;if(typeof i!=="string")throw Error("fixture.instrument.name \u5FC5\u987B\u662F\u5B57\u7B26\u4E32");let o=_(e.instrument.minOrderVolume===void 0?1:e.instrument.minOrderVolume,"fixture.instrument.minOrderVolume"),s=_(e.instrument.maxOrderVolume===void 0?1e5:e.instrument.maxOrderVolume,"fixture.instrument.maxOrderVolume");if(s<o)throw Error("fixture.instrument.maxOrderVolume \u5FC5\u987B\u4E0D\u5C0F\u4E8E minOrderVolume");let a=Ee(e.instrument.longMarginRatio===void 0?0.1:e.instrument.longMarginRatio,"fixture.instrument.longMarginRatio"),d=Ee(e.instrument.shortMarginRatio===void 0?0.1:e.instrument.shortMarginRatio,"fixture.instrument.shortMarginRatio"),c=e.instrument.isTrading===void 0?!0:e.instrument.isTrading;if(typeof c!=="boolean")throw Error("fixture.instrument.isTrading \u5FC5\u987B\u662F\u5E03\u5C14\u503C");let u=e.commission===void 0?void 0:pi(e.commission),l=e.setting===void 0?{}:ce(e.setting,"fixture.setting"),f=e.seedPrice===void 0?mi:E(e.seedPrice,"fixture.seedPrice"),h=e.tradingDay===void 0?li:X(e.tradingDay),m=/^([A-Z]+)\d+([A-Z]+)$/.exec(t.instrumentID),v=m?`${m[1]}_${m[2]}`:t.instrumentID.match(/^[A-Z]+/)?.[0]??"";if(!v)throw Error(`\u65E0\u6CD5\u4ECE ${t.instrumentID} \u63A8\u5BFC fixture \u4EA7\u54C1\u4EE3\u7801`);return{vtSymbol:t.vtSymbol,instrumentID:t.instrumentID,exchangeID:t.vtSymbol.split(".")[1],productID:v,setting:l,priceTick:r,size:n,name:i,minOrderVolume:o,maxOrderVolume:s,longMarginRatio:a,shortMarginRatio:d,isTrading:c,commission:u,seedPrice:f,tradingDay:h}}function Ge(e){let t=e.commission;if(!t)return null;return{instrumentID:e.instrumentID,exchangeID:e.exchangeID,investorRange:"1",brokerID:"test",investorID:"test",bizType:"1",investUnitID:"",openRatioByMoney:t.open.ratioByMoney,openRatioByVolume:t.open.perLot,closeRatioByMoney:t.close.ratioByMoney,closeRatioByVolume:t.close.perLot,closeTodayRatioByMoney:t.closeToday.ratioByMoney,closeTodayRatioByVolume:t.closeToday.perLot}}function pi(e){if(!ae(e))throw Error("fixture.commission \u5FC5\u987B\u662F\u5BF9\u8C61");return Te(e,["open","close","closeToday"],"fixture.commission"),{open:It(e.open,"fixture.commission.open"),close:It(e.close,"fixture.commission.close"),closeToday:It(e.closeToday,"fixture.commission.closeToday")}}function It(e,t){if(!ae(e))throw Error(`${t} \u5FC5\u987B\u662F\u5BF9\u8C61`);return Te(e,["ratioByMoney","perLot"],t),{ratioByMoney:Ee(e.ratioByMoney,`${t}.ratioByMoney`),perLot:Ee(e.perLot,`${t}.perLot`)}}function Ie(e,t,r){let n=-1;for(let i of e){if(i.code!==r)throw Error("\u6D4B\u8BD5 Bar \u5408\u7EA6\u4E0E fixture \u4E0D\u5339\u914D");if(i.barTime<=n)throw Error("\u6D4B\u8BD5 Bar \u5FC5\u987B\u6309\u65F6\u95F4\u4E25\u683C\u9012\u589E");if((i.barTime+(i.boundaryReason?0:60))*1000>t)throw Error("\u6D4B\u8BD5 Bar \u5C1A\u672A\u95ED\u5408\uFF0C\u4E0D\u80FD\u4F7F\u7528\u672A\u6765\u6570\u636E");n=i.barTime}}function Ke(e){let t=e.tradingDay;return Date.parse(`${t.slice(0,4)}-${t.slice(4,6)}-${t.slice(6,8)}T09:00:00+08:00`)}function Ot(e){let t=new Date(e+28800000);return`${t.getUTCFullYear()}${String(t.getUTCMonth()+1).padStart(2,"0")}${String(t.getUTCDate()).padStart(2,"0")}`}function H(e,t,r,n=Ke(e)/1000+r*60){if(t.timeframe!==void 0&&t.timeframe!=="1min")throw Error("bar.timeframe \u5FC5\u987B\u662F 1min");let i=E(t.close,"bar.close"),o=t.open===void 0?i:E(t.open,"bar.open"),s=t.high===void 0?Math.max(o,i):E(t.high,"bar.high"),a=t.low===void 0?Math.min(o,i):E(t.low,"bar.low");if(s<Math.max(o,i)||a>Math.min(o,i))throw Error("Bar OHLC \u5173\u7CFB\u975E\u6CD5");let d=t.volume===void 0?100+r:Ee(t.volume,"bar.volume"),c=t.barTime===void 0?n:T(t.barTime,"bar.barTime");return{code:$r(t.code??e.instrumentID),timeframe:"1min",barTime:c,open:o,high:s,low:a,close:i,volume:d,tradingDay:t.tradingDay===void 0?e.tradingDay:X(t.tradingDay),...t.boundaryReason?{boundaryReason:t.boundaryReason}:{}}}function De(e,t,r,n=Ke(e)+r*60000){let i=E(t.lastPrice,"tick.lastPrice"),o=t.datetime===void 0?n:T(t.datetime,"tick.datetime"),s=new Date(o+28800000),a=t.updateTime??[s.getUTCHours(),s.getUTCMinutes(),s.getUTCSeconds()].map((c)=>String(c).padStart(2,"0")).join(":");if(!/^(?:[01]\d|2[0-3]):[0-5]\d:[0-5]\d$/.test(a))throw Error("tick.updateTime \u5FC5\u987B\u662F HH:MM:SS");let d=t.updateMillisec===void 0?o%1000:T(t.updateMillisec,"tick.updateMillisec");if(d>999)throw Error("tick.updateMillisec \u5FC5\u987B\u5728 0-999 \u4E4B\u95F4");return{code:$r(t.code??e.instrumentID),exchangeID:t.exchangeID??e.exchangeID,productID:t.productID??e.productID,priceTick:t.priceTick===void 0?e.priceTick:E(t.priceTick,"tick.priceTick"),lastPrice:i,updateTime:a,updateMillisec:d,actionDay:t.actionDay===void 0?Ot(o):X(t.actionDay),tradingDay:t.tradingDay===void 0?e.tradingDay:X(t.tradingDay),volume:t.volume===void 0?100+r:T(t.volume,"tick.volume"),datetime:o,bidPrice1:je(t,"bidPrice1",i,E),bidVolume1:je(t,"bidVolume1",1000,T),askPrice1:je(t,"askPrice1",i,E),askVolume1:je(t,"askVolume1",1000,T),...t.upperLimitPrice===void 0?{}:{upperLimitPrice:E(t.upperLimitPrice,"tick.upperLimitPrice")},...t.lowerLimitPrice===void 0?{}:{lowerLimitPrice:E(t.lowerLimitPrice,"tick.lowerLimitPrice")},...t.rawActionDay===void 0?{}:{rawActionDay:t.rawActionDay},...t.receivedAt===void 0?{}:{receivedAt:T(t.receivedAt,"tick.receivedAt")},...t.dateSource===void 0?{}:{dateSource:t.dateSource},...t.tradingDaySource===void 0?{}:{tradingDaySource:t.tradingDaySource}}}function $r(e){if(typeof e!=="string"||!/^[A-Za-z][A-Za-z0-9]*$/.test(e))throw Error("\u884C\u60C5 code \u975E\u6CD5");return e}function je(e,t,r,n){if(!Object.hasOwn(e,t))return r;return e[t]===void 0?void 0:n(e[t],`tick.${t}`)}function Ye(e){return{instrumentID:e.instrumentID,exchangeID:e.exchangeID,productID:e.productID,productClass:"1",exchangeInstID:e.instrumentID,instrumentName:e.name,volumeMultiple:e.size,priceTick:e.priceTick,maxLimitOrderVolume:e.maxOrderVolume,minLimitOrderVolume:e.minOrderVolume,maxMarketOrderVolume:0,minMarketOrderVolume:0,longMarginRatio:e.longMarginRatio,shortMarginRatio:e.shortMarginRatio,maxMarginSideAlgorithm:"",strikePrice:0,optionsType:"",combinationType:"",deliveryYear:0,deliveryMonth:0,createDate:"",openDate:"",expireDate:"",startDelivDate:"",endDelivDate:"",instLifePhase:"1",isTrading:e.isTrading?1:0,positionType:"",positionDateType:"",underlyingInstrID:"",underlyingMultiple:1}}function We(e){if(e===void 0)return de();if(!ae(e))throw Error("initialState.inventory \u5FC5\u987B\u662F\u5BF9\u8C61");return Te(e,["longToday","longYesterday","shortToday","shortYesterday"],"initialState.inventory"),{longToday:e.longToday===void 0?0:T(e.longToday,"longToday"),longYesterday:e.longYesterday===void 0?0:T(e.longYesterday,"longYesterday"),shortToday:e.shortToday===void 0?0:T(e.shortToday,"shortToday"),shortYesterday:e.shortYesterday===void 0?0:T(e.shortYesterday,"shortYesterday")}}function de(){return{longToday:0,longYesterday:0,shortToday:0,shortYesterday:0}}function Mr(e){return e.longToday+e.longYesterday-e.shortToday-e.shortYesterday}function gi(e,t){let r=new Date(Date.UTC(Number(e.slice(0,4)),Number(e.slice(4,6))-1,Number(e.slice(6,8))+t));return`${r.getUTCFullYear()}${String(r.getUTCMonth()+1).padStart(2,"0")}${String(r.getUTCDate()).padStart(2,"0")}`}function X(e){if(typeof e!=="string"||!/^\d{8}$/.test(e))throw Error("fixture.tradingDay \u5FC5\u987B\u662F YYYYMMDD");if(gi(e,0)!==e)throw Error(`fixture.tradingDay \u975E\u6CD5: ${e}`);return e}function ce(e,t){if(!ae(e))throw Error(`${t} \u5FC5\u987B\u662F\u5BF9\u8C61`);try{Dt(e,t,new Set);let r=JSON.stringify(e);if(r===void 0)throw Error("\u4E0D\u53EF\u5E8F\u5217\u5316");return JSON.parse(r)}catch(r){throw Error(`${t} \u5FC5\u987B\u53EF JSON \u5E8F\u5217\u5316: ${r instanceof Error?r.message:String(r)}`)}}function Dt(e,t,r){if(e===null||typeof e==="string"||typeof e==="boolean")return;if(typeof e==="number"){if(!Number.isFinite(e))throw Error(`${t} \u5305\u542B\u975E\u6709\u9650\u6570\u5B57`);return}if(typeof e!=="object")throw Error(`${t} \u5305\u542B\u4E0D\u53EF\u5E8F\u5217\u5316\u7684 ${typeof e}`);if(r.has(e))throw Error(`${t} \u5305\u542B\u5FAA\u73AF\u5F15\u7528`);if(r.add(e),Array.isArray(e))for(let n=0;n<e.length;n++)Dt(e[n],`${t}[${n}]`,r);else{let n=Object.getPrototypeOf(e);if(n!==Object.prototype&&n!==null)throw Error(`${t} \u5FC5\u987B\u662F\u666E\u901A\u5BF9\u8C61\u6216\u6570\u7EC4`);for(let[i,o]of Object.entries(e))Dt(o,`${t}.${i}`,r)}r.delete(e)}function Te(e,t,r){let n=Object.keys(e).find((i)=>!t.includes(i));if(n)throw Error(`${r} \u4E0D\u652F\u6301\u5B57\u6BB5 "${n}"`)}function E(e,t){if(typeof e!=="number"||!Number.isFinite(e)||e<=0)throw Error(`${t} \u5FC5\u987B\u662F\u6B63\u6570`);return e}function _(e,t){if(!Number.isSafeInteger(e)||e<=0)throw Error(`${t} \u5FC5\u987B\u662F\u6B63\u6574\u6570`);return e}function T(e,t){if(!Number.isSafeInteger(e)||e<0)throw Error(`${t} \u5FC5\u987B\u662F\u975E\u8D1F\u6574\u6570`);return e}function Ee(e,t){if(typeof e!=="number"||!Number.isFinite(e)||e<0)throw Error(`${t} \u5FC5\u987B\u662F\u975E\u8D1F\u6570`);return e}function ae(e){return e!==null&&typeof e==="object"&&!Array.isArray(e)}class Oe{fixture;sequence;now;observations;phase="running";instrument;orders=new Map;trades=new Map;reportedOrders=new Map;deliveredTrades=new Set;orderHandlers=new Set;tradeHandlers=new Set;errorHandlers=new Set;reconcileHandlers=new Set;faultHandlers=new Set;inventories=new Map;tradingDay;nextSubmitFailure;nextCancelFailure;holdingReports=!1;reportSequence=0;reports=new Map;pending=new Set;deliveredReports=new Set;constructor(e,t,r,n,i,o){this.fixture=e;this.sequence=r;this.now=n;this.observations=i;if(this.inventories.set(e.vtSymbol,{...t}),this.tradingDay=e.tradingDay,this.instrument=Ye(e),o)this.reconcile({...o,reason:"initial"})}snapshot(){return{phase:this.phase,tradingDay:this.tradingDay,inventory:{...this.inventories.get(this.fixture.vtSymbol)??de()},orders:[...this.orders.values()].map(L),trades:[...this.trades.values()].map((e)=>({...e}))}}holdReports(){this.holdingReports=!0}resumeReports(){this.requireConnected(),this.holdingReports=!1;for(let e of[...this.pending])this.deliverReport(e)}pendingReports(){return[...this.pending].map((e)=>structuredClone(this.reports.get(e)))}deliverReport(e){if(this.requireConnected(),!this.pending.delete(e))throw Error(`Pending broker report does not exist: ${e}`);this.deliver(this.reports.get(e))}repeatReport(e){this.requireConnected();let t=this.reports.get(e);if(!t||!this.deliveredReports.has(e))throw Error(`Delivered broker report does not exist: ${e}`);this.deliver(t,!0)}async prepareInstrument(e,t){if(e!==this.fixture.instrumentID||t!==this.fixture.exchangeID)throw Error(`\u6D4B\u8BD5\u5408\u7EA6\u4E0D\u5339\u914D: ${e}.${t}`);return this.instrument}async prepareCommission(e,t){if(e!==this.fixture.instrumentID||t!==this.fixture.exchangeID)throw Error(`\u6D4B\u8BD5\u624B\u7EED\u8D39\u5408\u7EA6\u4E0D\u5339\u914D: ${e}.${t}`)}getInstrument(e){return e===this.fixture.instrumentID?this.instrument:null}getCommission(e,t){if(e!==this.fixture.instrumentID||t!==this.fixture.exchangeID)return null;return Ge(this.fixture)}async queryPositions(e){return{phase:this.phase,positions:this.positionSnapshot().filter((t)=>!e||t.instrumentID===e.toUpperCase())}}async queryOrders(e){return[...this.orders.values()].filter((t)=>!e||t.instrumentID===e.toUpperCase()).map((t)=>L(t))}submitOrder(e){if(this.requireConnected(),this.nextSubmitFailure){let o=this.nextSubmitFailure;throw this.nextSubmitFailure=void 0,Error(o)}let t,r;do t=String(++this.sequence.order),r=`CTP.${this.tradingDay}.1.1.${t}`;while(this.orders.has(r));let n=e.direction==="buy"?"long":"short",i={vtOrderId:r,identity:{tradingDay:this.tradingDay,frontID:1,sessionID:1,orderRef:t,instrumentID:this.fixture.instrumentID,exchangeID:this.fixture.exchangeID},vtSymbol:this.fixture.vtSymbol,instrumentID:this.fixture.instrumentID,exchangeID:this.fixture.exchangeID,orderSysID:`TEST-${t}`,side:e.direction,direction:n,offset:e.offsetFlag,price:e.price,volume:e.volume,traded:0,status:"submitting",statusMessage:"",datetime:this.now()};return this.orders.set(r,i),this.reportedOrders.set(r,L(i)),this.observations.submissions.push({vtOrderId:r,direction:n,offset:e.offsetFlag,price:e.price,volume:e.volume}),this.observations.record("submission",this.observations.submissions.at(-1)),{vtOrderId:r,orderRef:t}}cancelOrder(e){if(this.observations.cancelRequests.push(e),this.observations.record("cancel",{vtOrderId:e}),this.requireConnected(),this.nextCancelFailure){let t=this.nextCancelFailure;throw this.nextCancelFailure=void 0,Error(t)}}onOrder(e){return this.orderHandlers.add(e),()=>this.orderHandlers.delete(e)}onTrade(e){return this.tradeHandlers.add(e),()=>this.tradeHandlers.delete(e)}onOrderError(e){return this.errorHandlers.add(e),()=>this.errorHandlers.delete(e)}onReconciled(e){return this.reconcileHandlers.add(e),()=>this.reconcileHandlers.delete(e)}onFault(e){return this.faultHandlers.add(e),()=>this.faultHandlers.delete(e)}failNextSubmit(e="test submit failed"){this.nextSubmitFailure=e}rejectSubmit(e,t="test submit rejected"){let r=this.requireActiveOrder(e);if(r.traded!==0||this.tradedVolume(e)>0)throw Error("\u5DF2\u6210\u4EA4\u59D4\u6258\u4E0D\u80FD\u62D2\u5355");if(r.status="rejected",r.statusMessage=t,this.phase!=="running")return;this.reportedOrders.set(e,L(r)),this.queueReport({type:"error",value:{vtOrderId:e,orderRef:r.identity.orderRef,instrumentID:r.instrumentID,operation:"submit",message:t}})}rejectCancel(e,t="test cancel rejected"){let r=this.requireOrder(e);this.requireConnected(),this.queueReport({type:"error",value:{vtOrderId:e,orderRef:r.identity.orderRef,instrumentID:r.instrumentID,operation:"cancel",message:t}})}emitExternalOrder(e){if(this.orders.has(e.vtOrderId))throw Error(`\u6D4B\u8BD5\u59D4\u6258\u5DF2\u5B58\u5728: ${e.vtOrderId}`);this.emitOrder(e)}emitOrder(e){let t=this.normalizeOrder(e);this.orders.set(t.vtOrderId,t),this.publishOrder(t)}emitTrade(e){let t=this.recordTrade(e);this.publishTrade(t)}disconnect(){if(this.phase!=="faulted")this.phase="recovering"}connect(){this.phase="running",this.reportedOrders.clear(),this.deliveredTrades.clear(),this.nextSubmitFailure=void 0,this.nextCancelFailure=void 0,this.pending.clear(),this.holdingReports=!1,this.reconcile({reason:"initial"})}reconcile(e={}){if(this.phase==="faulted")throw Error("\u6D4B\u8BD5 Broker \u5DF2 fault\uFF0C\u5FC5\u987B\u91CD\u542F Runtime");this.phase="recovering",this.pending.clear();try{let t=e.tradingDay===void 0?this.tradingDay:X(e.tradingDay);if(t<this.tradingDay)throw Error("\u6D4B\u8BD5 Broker TradingDay \u4E0D\u80FD\u56DE\u9000");if(t!==this.tradingDay)for(let o of this.inventories.values())o.longYesterday+=o.longToday,o.longToday=0,o.shortYesterday+=o.shortToday,o.shortToday=0;this.tradingDay=t;let r=e.orders===void 0?[...this.orders.values()].filter((o)=>o.identity.tradingDay===t).map(L):e.orders.map((o)=>this.normalizeOrder(o));if(e.orders!==void 0){for(let o of this.orders.values())if(o.identity.tradingDay===t)this.orders.delete(o.vtOrderId);for(let o of r)this.orders.set(o.vtOrderId,o)}for(let o of e.trades??[])this.recordTrade(o);if(e.inventory!==void 0)this.inventories.set(this.fixture.vtSymbol,We(e.inventory));let n=[...this.trades.values()].filter((o)=>o.tradingDay===t),i={reason:e.reason??"reconnect",tradingDay:t,accounts:[],positions:this.positionSnapshot(),orders:r,trades:n,recoveredAt:this.now()};if(i.reason==="reconnect"){for(let o of this.reportedOrders.values())if(w(o)&&o.identity.tradingDay===t&&!r.some((s)=>s.vtOrderId===o.vtOrderId))throw Error(`\u6D3B\u52A8\u59D4\u6258\u672A\u51FA\u73B0\u5728\u6062\u590D\u5FEB\u7167: ${o.vtOrderId}`);for(let o of r)this.publishOrder(o,!0);for(let o of n)this.publishTrade(o,!0)}else{for(let o of r)this.reportedOrders.set(o.vtOrderId,L(o));for(let o of n)this.deliveredTrades.add(o.vtTradeId)}for(let o of this.reconcileHandlers)o(i);this.phase="running"}catch(t){throw this.fault(t instanceof Error?t.message:String(t)),t}}fault(e="test gateway fault"){if(this.phase==="faulted")return;this.phase="faulted";for(let t of this.faultHandlers)t(e)}acknowledge(e){this.updateOrder(e,(t)=>{if(t.traded!==0||this.tradedVolume(e)>0)throw Error("\u5DF2\u6210\u4EA4\u59D4\u6258\u4E0D\u80FD\u91CD\u65B0\u786E\u8BA4");t.status="notTraded",t.statusMessage="test acknowledged"})}partialFill(e,t,r){this.fillVolume(e,t,r)}fill(e,t){let r=this.requireActiveOrder(e);this.fillVolume(e,r.volume-Math.max(r.traded,this.tradedVolume(e)),t)}reject(e,t="test rejected"){this.updateOrder(e,(r)=>{if(r.traded!==0||this.tradedVolume(e)>0)throw Error("\u5DF2\u6210\u4EA4\u59D4\u6258\u4E0D\u80FD\u62D2\u5355");r.status="rejected",r.statusMessage=t})}cancel(e,t="test cancelled"){this.updateOrder(e,(r)=>{r.traded=Math.max(r.traded,this.tradedVolume(e)),r.status="cancelled",r.statusMessage=t})}failNextCancel(e="test cancel failed"){this.nextCancelFailure=e}settleActiveOrders(){for(let e of[...this.orders.values()])if(e.status==="submitting"||e.status==="notTraded"||e.status==="partTraded")this.cancel(e.vtOrderId,"test cleanup")}fillVolume(e,t,r){if(!Number.isInteger(t)||t<=0)throw Error("\u6210\u4EA4\u6570\u91CF\u5FC5\u987B\u662F\u6B63\u6574\u6570");let n=this.requireActiveOrder(e),i=n.volume-Math.max(n.traded,this.tradedVolume(e));if(t>i)throw Error(`\u6210\u4EA4\u6570\u91CF ${t} \u8D85\u8FC7\u5269\u4F59\u6570\u91CF ${i}`);let o=E(r??n.price,"\u6210\u4EA4\u4EF7\u683C");n.traded=n.volume-i+t,n.status=n.traded===n.volume?"allTraded":"partTraded",n.statusMessage="test filled",this.publishOrder(n);let s;do s=`TESTTRADE.${++this.sequence.trade}`;while(this.trades.has(s));this.emitTrade({vtTradeId:s,vtOrderId:n.vtOrderId,price:o,volume:t,datetime:this.now(),tradingDay:this.tradingDay})}updateOrder(e,t){let r=this.requireActiveOrder(e);t(r),this.publishOrder(r)}normalizeOrder(e){let t=this.orders.get(e.vtOrderId),r=hi({...this.fixture,tradingDay:this.tradingDay},{...e,vtSymbol:e.vtSymbol??t?.vtSymbol},this.now());if(t){if(t.vtSymbol!==r.vtSymbol||t.direction!==r.direction||t.offset!==r.offset||t.volume!==r.volume)throw Error(`\u6D4B\u8BD5\u59D4\u6258\u8EAB\u4EFD\u5B57\u6BB5\u53D1\u751F\u53D8\u5316: ${r.vtOrderId}`);if(r.identity={...t.identity},r.orderSysID=t.orderSysID,r.traded<t.traded||Ar(r)<Ar(t))return L(t)}return r}tradedVolume(e){let t=0;for(let r of this.trades.values())if(r.vtOrderId===e)t+=r.volume;return t}recordTrade(e){if(typeof e.vtTradeId!=="string"||!e.vtTradeId.trim())throw Error("\u6D4B\u8BD5\u6210\u4EA4 ID \u4E0D\u80FD\u4E3A\u7A7A");let t=this.trades.get(e.vtTradeId);if(t)return t;let r=this.requireOrder(e.vtOrderId),n=_(e.volume,"\u6210\u4EA4\u6570\u91CF"),i=this.tradedVolume(r.vtOrderId)+n;if(i>r.volume||!w(r)&&i>r.traded)throw Error("\u6D4B\u8BD5\u6210\u4EA4\u6570\u91CF\u8D85\u8FC7\u59D4\u6258\u5B9E\u9645\u6210\u4EA4\u8303\u56F4");let o={vtTradeId:e.vtTradeId,vtOrderId:r.vtOrderId,vtSymbol:r.vtSymbol,instrumentID:r.instrumentID,exchangeID:r.exchangeID,orderSysID:r.orderSysID,tradeID:e.vtTradeId,side:r.side,direction:r.direction,offset:r.offset,price:E(e.price??r.price,"\u6210\u4EA4\u4EF7\u683C"),volume:n,datetime:e.datetime===void 0?this.now():T(e.datetime,"\u6210\u4EA4\u65F6\u95F4"),tradingDay:e.tradingDay===void 0?this.tradingDay:X(e.tradingDay)};if(o.tradingDay!==this.tradingDay)throw Error("\u6D4B\u8BD5\u6210\u4EA4 TradingDay \u4E0E Broker \u4E0D\u4E00\u81F4");this.trades.set(o.vtTradeId,o);let s=this.inventories.get(o.vtSymbol)??de();return this.inventories.set(o.vtSymbol,s),yi(s,o.direction,o.offset,o.volume),o}positionSnapshot(){return[...this.inventories].flatMap(([e,t])=>fi({...this.fixture,...K(e),exchangeID:e.split(".")[1],tradingDay:this.tradingDay},t))}publishOrder(e,t=!1){if(!t&&this.phase!=="running")return;this.queueReport({type:"order",value:L(e)},t)}publishTrade(e,t=!1){if(!t&&this.phase!=="running")return;this.queueReport({type:"trade",value:{...e}},t)}queueReport(e,t=!1){let r={...e,id:`report-${++this.reportSequence}`,createdAt:this.now()};if(this.reports.set(r.id,r),this.observations.record("broker",{operation:"queued",report:r}),!this.holdingReports||t)this.deliver(r);else this.pending.add(r.id)}deliver(e,t=!1){if(this.deliveredReports.add(e.id),this.observations.record("broker",{operation:"delivered",duplicate:t,report:e}),e.type==="trade"){let i=e.value;if(!t&&this.deliveredTrades.has(i.vtTradeId))return;this.deliveredTrades.add(i.vtTradeId);for(let o of this.tradeHandlers)o({...i});return}if(e.type==="error"){for(let i of this.errorHandlers)i({...e.value});return}let r=e.value,n=this.reportedOrders.get(r.vtOrderId);if(!t&&n&&n.status===r.status&&n.traded===r.traded&&n.statusMessage===r.statusMessage&&n.orderSysID===r.orderSysID)return;this.reportedOrders.set(r.vtOrderId,L(r));for(let i of this.orderHandlers)i(L(r))}requireConnected(){if(this.phase!=="running")throw Error(`\u6D4B\u8BD5 Broker \u672A\u5C31\u7EEA: ${this.phase}`)}requireOrder(e){let t=this.orders.get(e);if(!t)throw Error(`\u6D4B\u8BD5\u59D4\u6258\u4E0D\u5B58\u5728: ${e}`);return t}requireActiveOrder(e){let t=this.requireOrder(e);if(!w(t))throw Error(`\u6D4B\u8BD5\u59D4\u6258\u5DF2\u7EC8\u6B62: ${e} (${t.status})`);return t}}function Ar(e){if(e.status==="submitting")return 0;if(e.status==="notTraded")return 1;if(e.status==="partTraded")return 2;return 3}function hi(e,t,r){if(typeof t.vtOrderId!=="string"||!t.vtOrderId.trim())throw Error("\u6D4B\u8BD5\u59D4\u6258 ID \u4E0D\u80FD\u4E3A\u7A7A");let{vtSymbol:n,instrumentID:i}=K(t.vtSymbol??e.vtSymbol),o=n.split(".")[1];if(t.direction!=="long"&&t.direction!=="short")throw Error("\u6D4B\u8BD5\u59D4\u6258\u65B9\u5411\u975E\u6CD5");let s=t.offset??"open";if(!["open","close","closeToday","closeYesterday"].includes(s))throw Error("\u6D4B\u8BD5\u59D4\u6258\u5F00\u5E73\u975E\u6CD5");let a=_(t.volume,"\u6D4B\u8BD5\u59D4\u6258\u6570\u91CF"),d=t.traded===void 0?0:T(t.traded,"\u6D4B\u8BD5\u59D4\u6258\u5DF2\u6210\u4EA4\u6570\u91CF"),c=t.status??"notTraded";if(!["submitting","notTraded","partTraded","allTraded","cancelled","rejected"].includes(c)||d>a||(c==="submitting"||c==="notTraded"||c==="rejected")&&d!==0||c==="partTraded"&&(d===0||d===a)||c==="allTraded"&&d!==a)throw Error("\u6D4B\u8BD5\u59D4\u6258\u72B6\u6001\u4E0E\u6210\u4EA4\u6570\u91CF\u4E0D\u4E00\u81F4");return{vtOrderId:t.vtOrderId,identity:{tradingDay:e.tradingDay,frontID:1,sessionID:1,orderRef:t.vtOrderId.split(".").at(-1),instrumentID:i,exchangeID:o},vtSymbol:n,instrumentID:i,exchangeID:o,orderSysID:`TEST-${t.vtOrderId}`,side:t.direction==="long"?"buy":"sell",direction:t.direction,offset:s,price:E(t.price,"\u6D4B\u8BD5\u59D4\u6258\u4EF7\u683C"),volume:a,traded:d,status:c,statusMessage:t.statusMessage??"",datetime:t.datetime===void 0?r:T(t.datetime,"\u6D4B\u8BD5\u59D4\u6258\u65F6\u95F4")}}function fi(e,t){let r=[],n=(i,o,s)=>{if(o+s===0)return;r.push({instrumentID:e.instrumentID,exchangeID:e.exchangeID,vtSymbol:e.vtSymbol,direction:i,hedgeFlag:"1",investUnitID:"",tradingDay:e.tradingDay,volume:o+s,todayVolume:o,yesterdayVolume:s,frozen:0,price:e.seedPrice,pnl:0,margin:0,positionCost:0})};return n("long",t.longToday,t.longYesterday),n("short",t.shortToday,t.shortYesterday),r}function yi(e,t,r,n){if(r==="open"){if(t==="long")e.longToday+=n;else e.shortToday+=n;return}let i=t==="short"?"longToday":"shortToday",o=t==="short"?"longYesterday":"shortYesterday";if(r==="closeToday")e[i]=Math.max(0,e[i]-n);else if(r==="closeYesterday")e[o]=Math.max(0,e[o]-n);else{let s=Math.min(e[o],n);e[o]-=s,e[i]=Math.max(0,e[i]-(n-s))}}function L(e){return{...e,identity:{...e.identity}}}class Qe extends Error{method;code;constructor(e,t,r){super(r);this.method=e;this.code=t;this.name="GatewayRpcError"}}var Je=(e)=>e.toUpperCase();function Re(e){return e.map((t)=>({...t,instrumentID:Je(t.instrumentID)}))}class Rt{transport;loginResult=null;connected=!1;queryQueue=Promise.resolve();lastQueryAt=0;minQueryIntervalMs;queryTimeoutMs;normalizeInstrumentID;cleanups;pendingQueries=new Set;disposed=!1;clock;constructor(e,t={}){this.transport=e;this.minQueryIntervalMs=t.minQueryIntervalMs??0,this.queryTimeoutMs=t.queryTimeoutMs??15000,this.normalizeInstrumentID=t.normalizeInstrumentID??((r)=>r),this.clock=t.clock??{now:Date.now,schedule:(r,n)=>{let i=setTimeout(r,n);return()=>clearTimeout(i)}},this.cleanups=[e.on("onDisconnected",()=>{this.connected=!1}),e.on("onReconnecting",()=>{this.connected=!1}),e.on("onReconnected",(r)=>{this.connected=!0,this.loginResult=r.params}),e.onExit(()=>{this.connected=!1})]}async login(e){let t=await this.request("login",e,"\u4EA4\u6613\u767B\u5F55\u5931\u8D25");return this.loginResult=t,this.connected=!0,t}async logout(e,t){await this.request("logout",{broker:e,user:t},"\u767B\u51FA\u5931\u8D25"),this.loginResult=null,this.connected=!1}async changePassword(e){await this.request("changePassword",e,"\u4FEE\u6539\u5BC6\u7801\u5931\u8D25")}async insertOrder(e){let t=this.loginResult,r=await this.request("insertOrder",this.normalizeParams(e),"\u4E0B\u5355\u5931\u8D25"),n=r.tradingDay??t?.tradingDay,i=r.frontID??t?.frontID,o=r.sessionID??t?.sessionID;if(!n||!i||!o)throw Error("\u4E0B\u5355\u6210\u529F\u4F46\u4EA4\u6613\u4F1A\u8BDD\u8EAB\u4EFD\u4E0D\u53EF\u7528");return{tradingDay:n,frontID:i,sessionID:o,orderRef:r.orderRef,requestID:r.requestID}}cancelOrder(e){return this.request("cancelOrder",this.normalizeParams(e),"\u64A4\u5355\u5931\u8D25")}queryAccount(e,t){return this.query(()=>this.requestAndWait("queryAccount",{broker:e,investorId:t},"onQueryAccountResult",(r)=>r.accounts??[],"\u67E5\u8BE2\u8D26\u6237\u5931\u8D25",!0))}queryPositions(e,t,r){return this.query(()=>this.requestAndWait("queryPosition",{broker:e,investorId:t,instrumentID:r?this.normalizeInstrumentID(r):""},"onQueryPositionResult",(n)=>Re(n.positions??[]),"\u67E5\u8BE2\u6301\u4ED3\u5931\u8D25",!0))}queryOrders(e){return this.query(()=>this.requestAndWait("queryOrder",this.normalizeParams(e),"onQueryOrderResult",(t)=>Re(t.orders??[]),"\u67E5\u8BE2\u59D4\u6258\u5931\u8D25",!0))}queryTrades(e){return this.query(()=>this.requestAndWait("queryTrade",this.normalizeParams(e),"onQueryTradeResult",(t)=>Re(t.trades??[]),"\u67E5\u8BE2\u6210\u4EA4\u5931\u8D25",!0))}querySettlementInfo(e){return this.query(()=>this.requestAndWait("querySettlementInfo",e,"onQuerySettlementInfoResult",(t)=>t.settlementInfos??t.settlements??[],"\u67E5\u8BE2\u7ED3\u7B97\u5355\u5931\u8D25",!0))}queryInstrument(e={}){return this.query(()=>this.requestAndWait("queryInstrument",this.normalizeParams(e),"onQueryInstrumentResult",(t)=>Re(t.instruments??[]),"\u67E5\u8BE2\u5408\u7EA6\u89C4\u683C\u5931\u8D25",!0,e.instrumentID||e.exchangeID||e.exchangeInstID||e.productID?this.queryTimeoutMs:60000))}queryCommissionRates(e){return this.query(()=>this.requestAndWait("queryInstrumentCommissionRate",this.normalizeParams(e),"onQueryCommissionRateResult",(t)=>Re(t.commissionRates??[]),"\u67E5\u8BE2\u624B\u7EED\u8D39\u7387\u5931\u8D25",!0,e.instrumentID?this.queryTimeoutMs:60000))}async queryCommissionRate(e){return(await this.queryCommissionRates(e))[0]??null}onOrder(e){return this.transport.on("onOrder",(t)=>{let r=t.params;e({...r,instrumentID:Je(r.instrumentID)})})}onTrade(e){return this.transport.on("onTrade",(t)=>{let r=t.params;e({...r,instrumentID:Je(r.instrumentID)})})}onOrderError(e){return this.transport.on("onOrderError",(t)=>{let r=t.params;e({...r,instrumentID:r.instrumentID?Je(r.instrumentID):void 0})})}onConnection(e,t){return this.transport.on(e,t)}dispose(){this.disposed=!0;for(let e of[...this.pendingQueries])e();for(let e of this.cleanups.splice(0))e()}query(e){let t=this.queryQueue.then(async()=>{if(this.disposed)throw Error("Trader gateway API disposed");let r=Math.max(0,this.minQueryIntervalMs-(this.clock.now()-this.lastQueryAt));if(r>0)await new Promise((n,i)=>{let o=()=>{s(),this.pendingQueries.delete(o),i(Error("Trader gateway API disposed"))},s=this.clock.schedule(()=>{this.pendingQueries.delete(o),n()},r);this.pendingQueries.add(o)});if(this.disposed)throw Error("Trader gateway API disposed");try{return await e()}finally{this.lastQueryAt=this.clock.now()}});return this.queryQueue=t.then(()=>{return},()=>{return}),t}requestAndWait(e,t,r,n,i,o=!1,s=this.queryTimeoutMs){return new Promise((a,d)=>{let c=null,u=null,l=null,f=[],h=()=>{c?.(),c=null,u?.(),u=null,this.pendingQueries.delete(m)},m=()=>{h(),d(Error("Trader gateway API disposed"))};this.pendingQueries.add(m),c=this.clock.schedule(()=>{h(),d(Error(`${e} \u67E5\u8BE2\u8D85\u65F6`))},s);let v=(p)=>{h();let k=p.params;if(k.ok===!1)d(Error(k.error??`${e} \u67E5\u8BE2\u5931\u8D25`));else a(n(p.params))};u=this.transport.on(r,(p)=>{if(!o){v(p);return}if(l===null){f.push(p);return}if(p.params.requestID===l)v(p)}),this.transport.request(e,t).then((p)=>{if(!p.ok){h(),d(Error(p.error?.msg??i));return}if(o){let k=p.data?.requestID;if(!Number.isInteger(k)){h(),d(Error(`${e} \u672A\u8FD4\u56DE\u6709\u6548 requestID`));return}l=k;let q=f.find((M)=>M.params.requestID===l);if(q)v(q)}}).catch((p)=>{h(),d(p)})})}async request(e,t,r){let n=await this.transport.request(e,t);if(!n.ok)throw new Qe(e,n.error?.code,n.error?.msg??r);return n.data}normalizeParams(e){if(!e.instrumentID&&!e.productID)return e;return{...e,...e.instrumentID?{instrumentID:this.normalizeInstrumentID(e.instrumentID)}:{},...e.productID?{productID:this.normalizeInstrumentID(e.productID)}:{}}}}var wi=28800000,Si=Number.MAX_VALUE/2,Br=1e5;class Ct extends Error{}function b(e,t){let r=e?.trim()??"";if(!r)throw Error(`${t} \u4E3A\u7A7A`);return r}function vi(e){if(!/^\d{8}$/.test(e))return!1;let t=Number(e.slice(0,4)),r=Number(e.slice(4,6)),n=Number(e.slice(6,8)),i=new Date(Date.UTC(t,r-1,n));return i.getUTCFullYear()===t&&i.getUTCMonth()===r-1&&i.getUTCDate()===n}function x(e,t){let r=e?.trim()??"";if(!vi(r))throw Error(`${t} \u975E\u6CD5: ${r}`);return r}function N(e,t){if(!Number.isInteger(e)||e<0)throw Error(`${t} \u975E\u6CD5: ${e}`);return e}function Xe(e,t){if(!Number.isInteger(e)||e<-2147483648||e>2147483647)throw Error(`${t} \u975E\u6CD5: ${e}`);return e}function Ze(e,t){if(!Number.isFinite(e))throw Error(`${t} \u975E\u6CD5: ${e}`);return e}function Pt(e,t){if(!Number.isFinite(e)||e<=0||e>=Si)throw Error(`${t} \u975E\u6CD5: ${e}`);return e}function $t(e,t){if(!Number.isInteger(e)||e<=0)throw Error(`${t} \u975E\u6CD5: ${e}`);return e}function Nr(e,t,r){let n=x(e,`${r}\u65E5\u671F`),i=/^(\d{2}):(\d{2}):(\d{2})$/.exec(t);if(!i)throw Error(`${r}\u65F6\u95F4\u975E\u6CD5: ${t}`);let o=Number(i[1]),s=Number(i[2]),a=Number(i[3]);if(o>23||s>59||a>59)throw Error(`${r}\u65F6\u95F4\u975E\u6CD5: ${t}`);return Date.UTC(Number(n.slice(0,4)),Number(n.slice(4,6))-1,Number(n.slice(6,8)),o,s,a)-wi}function Fr(e){if(e==="0")return{side:"buy",direction:"long"};if(e==="1")return{side:"sell",direction:"short"};throw Error(`CTP Direction \u4E0D\u652F\u6301: ${e}`)}function Vr(e){switch(e){case"0":return"open";case"1":return"close";case"3":return"closeToday";case"4":return"closeYesterday";default:throw Error(`CTP OffsetFlag \u4E0D\u652F\u6301: ${e}`)}}function ki(e){if(!["0","1","2","3","4","5","6"].includes(e.orderSubmitStatus))throw Error(`CTP OrderSubmitStatus \u4E0D\u652F\u6301: ${e.orderSubmitStatus}`);if(e.orderSubmitStatus==="4")return"rejected";switch(e.orderStatus){case"0":return"allTraded";case"1":return"partTraded";case"2":case"4":case"5":return"cancelled";case"3":case"b":case"c":return"notTraded";case"a":return"submitting";default:throw Error(`CTP OrderStatus \u4E0D\u652F\u6301: ${e.orderStatus}`)}}function Hr(e,t){return`${e}|${t}`}function Lr(e,t){return`${e}|${t}`}function xt(e){let t=x(e.tradingDay,"\u59D4\u6258 TradingDay"),r=N(e.frontID,"\u59D4\u6258 FrontID"),n=Xe(e.sessionID,"\u59D4\u6258 SessionID"),i=b(e.orderRef,"\u59D4\u6258 OrderRef");return`CTP.${t}.${r}.${n}.${i}`}function _t(e){let t=b(e.instrumentID,"\u59D4\u6258 InstrumentID").toUpperCase(),r=b(e.exchangeID,"\u59D4\u6258 ExchangeID").toUpperCase(),n=x(e.tradingDay,"\u59D4\u6258 TradingDay"),i=b(e.orderRef,"\u59D4\u6258 OrderRef"),o={tradingDay:n,frontID:N(e.frontID,"\u59D4\u6258 FrontID"),sessionID:Xe(e.sessionID,"\u59D4\u6258 SessionID"),orderRef:i,instrumentID:t,exchangeID:r},s=Fr(e.direction),a=$t(e.volumeTotalOriginal,"\u59D4\u6258\u6570\u91CF"),d=N(e.volumeTraded,"\u59D4\u6258\u6210\u4EA4\u6570\u91CF");if(d>a)throw Error(`\u59D4\u6258\u6210\u4EA4\u6570\u91CF\u5927\u4E8E\u59D4\u6258\u6570\u91CF: ${d}/${a}`);return{vtOrderId:xt(o),identity:o,vtSymbol:`${t}.${r}`,instrumentID:t,exchangeID:r,orderSysID:e.orderSysID.trim(),...s,offset:Vr(e.combOffsetFlag),price:Pt(e.limitPrice,"\u59D4\u6258\u4EF7\u683C"),volume:a,traded:d,status:ki(e),statusMessage:e.statusMsg,datetime:Nr(e.insertDate,e.insertTime,"\u59D4\u6258"),...e.traceId?{traceId:e.traceId}:{}}}function Ti(e,t,r){let n=b(e.instrumentID,"\u6210\u4EA4 InstrumentID").toUpperCase(),i=b(e.exchangeID,"\u6210\u4EA4 ExchangeID").toUpperCase(),o=x(e.tradingDay||r,"\u6210\u4EA4 TradingDay"),s=b(e.orderSysID,"\u6210\u4EA4 OrderSysID"),a=b(e.orderRef,"\u6210\u4EA4 OrderRef"),d=t(i,s,o,a);if(!d)throw new Ct(`\u6210\u4EA4\u65E0\u6CD5\u5173\u8054\u59D4\u6258: ${i}/${s}/${a}`);let c=b(e.tradeID,"\u6210\u4EA4 TradeID"),u=Fr(e.direction);return{vtTradeId:`CTP.${o}.${i}.${c}`,vtOrderId:d,vtSymbol:`${n}.${i}`,instrumentID:n,exchangeID:i,orderSysID:s,tradeID:c,...u,offset:Vr(e.offsetFlag),price:Pt(e.price,"\u6210\u4EA4\u4EF7\u683C"),volume:$t(e.volume,"\u6210\u4EA4\u6570\u91CF"),datetime:Nr(e.tradeDate,e.tradeTime,"\u6210\u4EA4"),tradingDay:o,...e.traceId?{traceId:e.traceId}:{}}}function Ei(e,t=new Map){let r=new Map;for(let n of e){let i=b(n.instrumentID,"\u6301\u4ED3 InstrumentID").toUpperCase(),o=b(n.exchangeID,`\u6301\u4ED3 ${i} ExchangeID`).toUpperCase(),s=N(n.position,`\u6301\u4ED3 ${i} Position`),a=N(n.todayPosition,`\u6301\u4ED3 ${i} TodayPosition`);if(N(n.ydPosition,`\u6301\u4ED3 ${i} YdPosition`),a>s)throw Error(`\u6301\u4ED3 ${i} TodayPosition \u5927\u4E8E Position`);if(n.positionDate!=="1"&&n.positionDate!=="2")throw Error(`\u6301\u4ED3 ${i} PositionDate \u4E0D\u652F\u6301: ${n.positionDate}`);if(n.direction==="1"){if(s!==0)throw Error(`\u6682\u4E0D\u652F\u6301\u51C0\u6301\u4ED3\u8BB0\u5F55: ${i}`);continue}let d=n.direction==="2"?"long":n.direction==="3"?"short":(()=>{throw Error(`\u6301\u4ED3 ${i} PosiDirection \u4E0D\u652F\u6301: ${n.direction}`)})(),c=b(n.hedgeFlag,`\u6301\u4ED3 ${i} HedgeFlag`),u=n.investUnitID.trim(),l=x(n.tradingDay,`\u6301\u4ED3 ${i} TradingDay`),f=`${i}|${o}|${d}|${c}|${u}`,h=r.get(f);if(!h)h={instrumentID:i,exchangeID:o,direction:d,hedgeFlag:c,investUnitID:u,tradingDay:l,volume:0,yesterdayVolume:0,frozen:0,pnl:0,margin:0,positionCost:0},r.set(f,h);else if(h.tradingDay!==l)throw Error(`\u6301\u4ED3 ${i} \u6DF7\u5165\u591A\u4E2A TradingDay`);if(h.volume+=s,o==="SHFE"||o==="INE"){if(n.ydPosition>0&&a===0)h.yesterdayVolume+=s}else h.yesterdayVolume+=s-a;h.frozen+=d==="long"?N(n.shortFrozen,`\u6301\u4ED3 ${i} ShortFrozen`):N(n.longFrozen,`\u6301\u4ED3 ${i} LongFrozen`),h.pnl+=Ze(n.positionProfit,`\u6301\u4ED3 ${i} PositionProfit`),h.margin+=Ze(n.useMargin,`\u6301\u4ED3 ${i} UseMargin`),h.positionCost+=Ze(n.positionCost,`\u6301\u4ED3 ${i} PositionCost`)}return[...r.values()].map((n)=>{if(n.yesterdayVolume>n.volume)throw Error(`\u6301\u4ED3 ${n.instrumentID} \u6628\u4ED3\u5927\u4E8E\u603B\u4ED3`);let i=t.get(n.instrumentID)?.volumeMultiple??0,o=n.volume>0&&i>0?n.positionCost/(n.volume*i):0;return{instrumentID:n.instrumentID,exchangeID:n.exchangeID,vtSymbol:`${n.instrumentID}.${n.exchangeID}`,direction:n.direction,hedgeFlag:n.hedgeFlag,investUnitID:n.investUnitID,tradingDay:n.tradingDay,volume:n.volume,todayVolume:n.volume-n.yesterdayVolume,yesterdayVolume:n.yesterdayVolume,frozen:n.frozen,price:o,pnl:n.pnl,margin:n.margin,positionCost:n.positionCost}})}function U(e){return e.status==="submitting"||e.status==="notTraded"||e.status==="partTraded"}class Mt{api;options;contracts=new Map;orders=new Map;orderIdBySys=new Map;orderIdByRef=new Map;ambiguousOrderRefs=new Set;seenTrades=new Set;tradeLedgerDay="";pendingCancels=new Set;unresolvedTrades=[];pendingEvents=[];orderHandlers=new Set;tradeHandlers=new Set;errorHandlers=new Set;phaseHandlers=new Set;reconcileHandlers=new Set;faultHandlers=new Set;cleanups=[];session=null;currentSnapshot=null;recoveryTask=null;recoveryObservedOrderIds=null;_phase="idle";constructor(e,t){this.api=e;this.options=t;b(t.broker,"\u9002\u914D\u5668 BrokerID"),b(t.investorId,"\u9002\u914D\u5668 InvestorID"),this.cleanups.push(e.onOrder((r)=>this.receive({kind:"order",value:r})),e.onTrade((r)=>this.receive({kind:"trade",value:r})),e.onOrderError((r)=>this.receive({kind:"error",value:r})),e.onConnection("onDisconnected",()=>this.beginRecovery()),e.onConnection("onReconnecting",()=>this.beginRecovery()),e.onConnection("onReconnected",(r)=>{try{let n=r.params;this.setSession(n),this.reconcile(!0).catch((i)=>this.fail(i))}catch(n){this.fail(n)}}),e.transport.on("onReconnectFailed",(r)=>{this.fail(Error(String(r.params.error??"CTP \u91CD\u8FDE\u5931\u8D25")))}))}get phase(){return this._phase}get snapshot(){return this.currentSnapshot}async initialize(e){return this.setSession(e),this.reconcile(!1)}registerInstrument(e){this.contracts.set(e.instrumentID.toUpperCase(),e)}async queryPositions(e){this.ensureReady();let t=await this.api.queryPositions(this.options.broker,this.options.investorId,e);return this.normalizePositions(t)}async queryOrders(e){this.ensureReady();let r=(await this.api.queryOrders({broker:this.options.broker,investorId:this.options.investorId,instrumentID:e})).map((i)=>(this.validateOwner(i,"\u59D4\u6258"),this.acceptOrder(_t(i),!1))),n=new Map(this.cachedOrders(e).map((i)=>[i.vtOrderId,i]));for(let i of r)n.set(i.vtOrderId,i);return[...n.values()].sort((i,o)=>o.datetime-i.datetime)}cachedOrders(e){let t=e?.toUpperCase();return[...this.orders.values()].filter((r)=>!t||r.instrumentID===t).sort((r,n)=>n.datetime-r.datetime)}async queryAccounts(){this.ensureReady();let e=await this.api.queryAccount(this.options.broker,this.options.investorId);return this.validateAccounts(e,this.requireSession().tradingDay),e}async queryTrades(e){return this.ensureReady(),(await this.api.queryTrades({broker:this.options.broker,investorId:this.options.investorId,instrumentID:e})).map((r)=>(this.validateOwner(r,"\u6210\u4EA4"),this.normalizeTrade(r)))}submitOrder(e){if(this.ensureReady(),e.direction!=="buy"&&e.direction!=="sell")throw Error(`\u59D4\u6258\u65B9\u5411\u4E0D\u652F\u6301: ${String(e.direction)}`);if(!["open","close","closeToday","closeYesterday"].includes(e.offsetFlag))throw Error(`\u59D4\u6258\u5F00\u5E73\u4E0D\u652F\u6301: ${String(e.offsetFlag)}`);Pt(e.price,"\u59D4\u6258\u4EF7\u683C"),$t(e.volume,"\u59D4\u6258\u6570\u91CF");let t=this.requireSession(),r={tradingDay:x(t.tradingDay,"\u767B\u5F55 TradingDay"),frontID:N(t.frontID,"\u767B\u5F55 FrontID"),sessionID:Xe(t.sessionID,"\u767B\u5F55 SessionID"),orderRef:b(e.orderRef,"\u59D4\u6258 OrderRef"),instrumentID:b(e.instrumentID,"\u59D4\u6258 InstrumentID").toUpperCase(),exchangeID:b(e.exchangeID,"\u59D4\u6258 ExchangeID").toUpperCase()},n=xt(r);return this.bindOrderRef(r.tradingDay,r.orderRef,n),this.orders.set(n,{vtOrderId:n,identity:r,vtSymbol:`${r.instrumentID}.${r.exchangeID}`,instrumentID:r.instrumentID,exchangeID:r.exchangeID,orderSysID:"",side:e.direction,direction:e.direction==="buy"?"long":"short",offset:e.offsetFlag,price:e.price,volume:e.volume,traded:0,status:"submitting",statusMessage:"",datetime:(this.options.now??Date.now)(),...e.traceId?{traceId:e.traceId}:{}}),this.api.insertOrder(e).then((i)=>{if(i.tradingDay!==r.tradingDay||i.frontID!==r.frontID||i.sessionID!==r.sessionID||i.orderRef!==r.orderRef)this.fail(Error(`\u59D4\u6258 ${n} \u7684\u4F1A\u8BDD\u8EAB\u4EFD\u53D1\u751F\u53D8\u5316`))}).catch((i)=>{if(this._phase==="closed")return;let o=i instanceof Error?i.message:String(i);if(this.beginRecovery(),i instanceof Qe)this.emitError({vtOrderId:n,orderRef:r.orderRef,instrumentID:r.instrumentID,operation:"submit",message:o});else{let s=this.orders.get(n);if(s&&U(s)){let a={...s,statusMessage:`\u62A5\u5355\u7ED3\u679C\u5F85\u786E\u8BA4: ${o}`};this.orders.set(n,a),this.emitOrder(a)}}this.reconcileAfterRequestFailure()}),{vtOrderId:n,orderRef:r.orderRef}}cancelOrder(e){this.ensureReady();let t=this.orders.get(e);if(!t)throw Error(`\u627E\u4E0D\u5230\u5B9E\u76D8\u59D4\u6258: ${e}`);if(!U(t))throw Error(`\u59D4\u6258\u5DF2\u7EC8\u7ED3\uFF0C\u4E0D\u80FD\u64A4\u5355: ${e}`);this.pendingCancels.add(e),this.api.cancelOrder({orderRef:t.identity.orderRef,frontID:t.identity.frontID,sessionID:t.identity.sessionID,exchangeID:t.identity.exchangeID,instrumentID:t.identity.instrumentID}).catch((r)=>{if(this._phase==="closed")return;this.emitError({vtOrderId:e,orderRef:t.identity.orderRef,instrumentID:t.instrumentID,operation:"cancel",message:r instanceof Error?r.message:String(r)}),this.reconcileAfterRequestFailure()})}onOrder(e){return this.orderHandlers.add(e),()=>this.orderHandlers.delete(e)}onTrade(e){return this.tradeHandlers.add(e),()=>this.tradeHandlers.delete(e)}onOrderError(e){return this.errorHandlers.add(e),()=>this.errorHandlers.delete(e)}onPhase(e){return this.phaseHandlers.add(e),()=>this.phaseHandlers.delete(e)}onReconciled(e){return this.reconcileHandlers.add(e),()=>this.reconcileHandlers.delete(e)}onFault(e){return this.faultHandlers.add(e),()=>this.faultHandlers.delete(e)}close(){if(this._phase==="closed")return;this.setPhase("closed");for(let e of this.cleanups.splice(0))e();this.pendingEvents.length=0,this.unresolvedTrades.length=0,this.orderHandlers.clear(),this.tradeHandlers.clear(),this.errorHandlers.clear(),this.phaseHandlers.clear(),this.reconcileHandlers.clear(),this.faultHandlers.clear()}beginRecovery(){if(this._phase==="closed"||this._phase==="faulted")return;this.setPhase("recovering")}reconcileAfterRequestFailure(){if(this.beginRecovery(),this.api.connected)this.reconcile(!0).catch((e)=>this.fail(e))}async reconcile(e){if(this.recoveryTask)return this.recoveryTask;let t=this.performReconcile(e);this.recoveryTask=t;try{return await t}finally{if(this.recoveryTask===t)this.recoveryTask=null,this.recoveryObservedOrderIds=null}}async performReconcile(e){let t=this.requireSession();this.recoveryObservedOrderIds=new Set,this.setPhase("recovering");let r=await this.api.queryOrders({broker:this.options.broker,investorId:this.options.investorId}),n=new Map(this.orders);this.orderIdBySys.clear(),this.orderIdByRef.clear(),this.ambiguousOrderRefs.clear();let i=r.map((m)=>(this.validateOwner(m,"\u59D4\u6258"),this.acceptOrder(_t(m),!1))),s=(await this.api.queryTrades({broker:this.options.broker,investorId:this.options.investorId})).map((m)=>(this.validateOwner(m,"\u6210\u4EA4"),this.normalizeTrade(m))),a=[];for(let m of s){if(this.seenTrades.has(m.vtTradeId))continue;a.push(m),this.rememberTrade(m)}let d=await this.api.queryPositions(this.options.broker,this.options.investorId),c=this.normalizePositions(d),u=await this.api.queryAccount(this.options.broker,this.options.investorId);if(this.validateAccounts(u,t.tradingDay),this._phase==="closed"||this._phase==="faulted")throw Error(`CTP \u6062\u590D\u5DF2\u7EC8\u6B62\uFF08${this._phase}\uFF09`);let l={reason:e?"reconnect":"initial",tradingDay:x(t.tradingDay,"\u767B\u5F55 TradingDay"),accounts:u,positions:c,orders:i,trades:s,recoveredAt:(this.options.now??Date.now)()};if(this.currentSnapshot=l,e){for(let m of i){let v=n.get(m.vtOrderId);if(!v||this.orderFingerprint(v)!==this.orderFingerprint(m))this.emitOrder(m)}for(let m of a)this.emitTrade(m)}let f=this.pendingEvents.splice(0);for(let m of f)this.process(m);if(this.flushUnresolvedTrades(),this.unresolvedTrades.length>0)throw Error(`${this.unresolvedTrades.length} \u7B14\u6210\u4EA4\u65E0\u6CD5\u5173\u8054\u59D4\u6258`);let h=this.recoveryObservedOrderIds;for(let[m,v]of n)if(v.identity.tradingDay===l.tradingDay&&U(v)&&this.orders.has(m)&&!h.has(m))throw Error(`\u6D3B\u52A8\u59D4\u6258\u672A\u51FA\u73B0\u5728\u6062\u590D\u5FEB\u7167: ${m}`);l.orders=[...h].map((m)=>this.orders.get(m)).filter((m)=>m!==void 0&&m.identity.tradingDay===l.tradingDay);for(let m of this.reconcileHandlers)m(l);return this.setPhase("ready"),l}receive(e){if(this._phase==="closed"||this._phase==="faulted")return;if(this._phase!=="ready"){if(this.pendingEvents.length>=Br){this.fail(Error("CTP \u6062\u590D\u671F\u95F4\u4E8B\u4EF6\u7F13\u5B58\u6EA2\u51FA"));return}this.pendingEvents.push(e);return}try{this.process(e)}catch(t){this.fail(t)}}process(e){if(e.kind==="order")this.validateOwner(e.value,"\u59D4\u6258"),this.acceptOrder(_t(e.value),!0),this.flushUnresolvedTrades();else if(e.kind==="trade")this.validateOwner(e.value,"\u6210\u4EA4"),this.processTrade(e.value,!0);else this.processError(e.value)}acceptOrder(e,t){let r=this.orders.get(e.vtOrderId),n=e;if(r){if(r.instrumentID!==e.instrumentID||r.exchangeID!==e.exchangeID||r.side!==e.side||r.offset!==e.offset||r.volume!==e.volume)throw Error(`\u59D4\u6258\u8EAB\u4EFD\u5B57\u6BB5\u53D1\u751F\u53D8\u5316: ${e.vtOrderId}`);if(r.orderSysID&&e.orderSysID&&r.orderSysID!==e.orderSysID)throw Error(`\u59D4\u6258 OrderSysID \u53D1\u751F\u53D8\u5316: ${e.vtOrderId}`);if(e.traded<r.traded||this.orderStage(e)<this.orderStage(r))n=r;else n={...e,orderSysID:e.orderSysID||r.orderSysID,...e.traceId||!r.traceId?{}:{traceId:r.traceId}}}if(this.orders.set(n.vtOrderId,n),this.recoveryObservedOrderIds?.add(n.vtOrderId),this.bindOrderRef(n.identity.tradingDay,n.identity.orderRef,n.vtOrderId),n.orderSysID)this.orderIdBySys.set(Lr(n.exchangeID,n.orderSysID),n.vtOrderId);if(!U(n))this.pendingCancels.delete(n.vtOrderId);if(t&&(!r||this.orderFingerprint(r)!==this.orderFingerprint(n)))this.emitOrder(n);return n}normalizeTrade(e){return Ti(e,(t,r,n,i)=>this.orderIdBySys.get(Lr(t,r))??this.orderIdByRef.get(Hr(n,i))??null,this.session?.tradingDay)}bindOrderRef(e,t,r){let n=Hr(e,t);if(this.ambiguousOrderRefs.has(n))return;let i=this.orderIdByRef.get(n);if(i&&i!==r){this.orderIdByRef.delete(n),this.ambiguousOrderRefs.add(n);return}this.orderIdByRef.set(n,r)}normalizePositions(e){let t=x(this.requireSession().tradingDay,"\u767B\u5F55 TradingDay");for(let r of e)if(this.validateOwner(r,"\u6301\u4ED3"),x(r.tradingDay,`\u6301\u4ED3 ${r.instrumentID} TradingDay`)!==t)throw Error(`\u6301\u4ED3 TradingDay \u4E0E\u767B\u5F55\u4F1A\u8BDD\u4E0D\u4E00\u81F4: ${r.tradingDay}/${t}`);return Ei(e,this.contracts)}validateOwner(e,t){let r=b(e.brokerID,`${t} BrokerID`),n=b(e.investorID,`${t} InvestorID`);if(r!==this.options.broker||n!==this.options.investorId)throw Error(`${t}\u8D26\u6237\u8EAB\u4EFD\u4E0D\u5339\u914D: ${r}/${n}`)}validateAccounts(e,t){let r=x(t,"\u767B\u5F55 TradingDay");if(e.length===0)throw Error("\u8D26\u6237\u67E5\u8BE2\u8FD4\u56DE\u7A7A\u7ED3\u679C");for(let n of e){let i=b(n.brokerID,"\u8D26\u6237 BrokerID");if(b(n.accountID,"\u8D26\u6237 AccountID"),i!==this.options.broker)throw Error(`\u8D26\u6237 BrokerID \u4E0D\u5339\u914D: ${i}`);if(x(n.tradingDay,"\u8D26\u6237 TradingDay")!==r)throw Error(`\u8D26\u6237 TradingDay \u4E0E\u767B\u5F55\u4F1A\u8BDD\u4E0D\u4E00\u81F4: ${n.tradingDay}/${r}`);for(let[o,s]of Object.entries({preBalance:n.preBalance,balance:n.balance,available:n.available,currMargin:n.currMargin,frozenMargin:n.frozenMargin,frozenCash:n.frozenCash,frozenCommission:n.frozenCommission,closeProfit:n.closeProfit,positionProfit:n.positionProfit,commission:n.commission,deposit:n.deposit,withdraw:n.withdraw}))Ze(s,`\u8D26\u6237 ${o}`)}}processTrade(e,t){let r;try{r=this.normalizeTrade(e)}catch(n){if(n instanceof Ct){if(this.unresolvedTrades.length>=Br)throw Error("\u65E0\u6CD5\u5173\u8054\u7684\u6210\u4EA4\u7F13\u5B58\u6EA2\u51FA");this.unresolvedTrades.push(e);return}throw n}if(this.seenTrades.has(r.vtTradeId))return;if(this.rememberTrade(r),t)this.emitTrade(r)}flushUnresolvedTrades(){if(this.unresolvedTrades.length===0)return;let e=this.unresolvedTrades.splice(0);for(let t of e)this.processTrade(t,!0)}processError(e){let t=this.requireSession(),r=b(e.orderRef,"\u9519\u8BEF\u56DE\u62A5 OrderRef"),n=xt({...t,orderRef:r}),i=this.pendingCancels.has(n)?"cancel":"submit";this.emitError({vtOrderId:n,orderRef:r,...e.instrumentID?{instrumentID:e.instrumentID.toUpperCase()}:{},operation:i,message:e.errorMsg})}rememberTrade(e){if(!this.tradeLedgerDay||e.tradingDay>this.tradeLedgerDay){if(this.tradeLedgerDay)this.seenTrades.clear();this.tradeLedgerDay=e.tradingDay}this.seenTrades.add(e.vtTradeId)}orderFingerprint(e){return`${e.status}|${e.traded}|${e.orderSysID}|${e.statusMessage}`}orderStage(e){switch(e.status){case"submitting":return 0;case"notTraded":return 1;case"partTraded":return 2;case"allTraded":case"cancelled":case"rejected":return 3}}ensureReady(){if(this._phase!=="ready")throw Error(`CTP \u4EA4\u6613\u9002\u914D\u5668\u672A\u5C31\u7EEA\uFF08${this._phase}\uFF09`)}requireSession(){if(!this.session)throw Error("CTP \u4EA4\u6613\u4F1A\u8BDD\u4E0D\u53EF\u7528");return this.session}setSession(e){x(e.tradingDay,"\u767B\u5F55 TradingDay"),N(e.frontID,"\u767B\u5F55 FrontID"),Xe(e.sessionID,"\u767B\u5F55 SessionID"),this.session=e}setPhase(e){if(this._phase===e)return;if(this._phase==="closed")return;if(this._phase==="faulted"&&e!=="closed")return;this._phase=e;for(let t of this.phaseHandlers)t(e)}fail(e){if(this._phase==="closed"||this._phase==="faulted")return;let t=e instanceof Error?e.message:String(e);this.setPhase("faulted");for(let r of this.faultHandlers)r(t)}emitOrder(e){for(let t of this.orderHandlers)t(e)}emitTrade(e){for(let t of this.tradeHandlers)t(e)}emitError(e){this.pendingCancels.delete(e.vtOrderId);let t=this.orders.get(e.vtOrderId);if(t&&U(t)){let r=e.operation==="submit"?{...t,status:"rejected",statusMessage:e.message}:{...t,statusMessage:`\u64A4\u5355\u5931\u8D25: ${e.message}`};this.orders.set(e.vtOrderId,r),this.emitOrder(r)}for(let r of this.errorHandlers)r(e)}}var At={queryOrder:{event:"onQueryOrderResult",field:"orders"},queryTrade:{event:"onQueryTradeResult",field:"trades"},queryPosition:{event:"onQueryPositionResult",field:"positions"},queryAccount:{event:"onQueryAccountResult",field:"accounts"}};class qr{session;clock;trace;requests=[];pending=new Map;handlers=new Map;exits=new Set;held=new Set;waiters=new Set;state;constructor(e,t,r,n={}){this.session=e;this.clock=t;this.trace=r;this.state=structuredClone(n)}request(e,t,r=30000){let n={id:this.requests.length+1,method:e,params:structuredClone(t),now:this.clock.now};return this.requests.push(n),this.trace.record("broker",{operation:"rpc",request:n}),new Promise((i,o)=>{let s=this.clock.schedule(()=>{this.pending.delete(n.id),o(Error(`Test gateway ${e} request timed out`))},r);this.pending.set(n.id,{request:n,resolve:i,reject:o,cancelTimeout:s});for(let a of this.waiters)if(a.method===e)this.waiters.delete(a),a.resolve(structuredClone(n));if(!this.held.has(e))this.complete(n.id)})}pendingRequests(){return[...this.pending.values()].map((e)=>structuredClone(e.request))}waitForRequest(e){let t=this.pendingRequests().find((r)=>r.method===e);return t?Promise.resolve(t):new Promise((r,n)=>this.waiters.add({method:e,resolve:r,reject:n}))}setSnapshot(e){this.state={...this.state,...structuredClone(e)}}hold(e){this.held.add(e)}resume(e){this.held.delete(e);for(let{request:t}of[...this.pending.values()])if(t.method===e)this.complete(t.id)}reply(e,t){let r=this.pending.get(e);if(!r)throw Error(`Pending RPC does not exist: ${e}`);this.pending.delete(e),r.cancelTimeout();let n=r.request.method==="insertOrder"?{...this.session,orderRef:r.request.params.orderRef,requestID:e}:{requestID:e},i={id:e,...t??{ok:!0,data:n}};this.trace.record("broker",{operation:"rpcReply",response:i}),r.resolve(i)}completeQuery(e,t){let r=this.requests.find((o)=>o.id===e);if(!r||!Object.hasOwn(At,r.method))throw Error(`Query RPC does not exist: ${e}`);let n=At[r.method];if(this.pending.has(e))this.reply(e);let i=n.field==="accounts"?[{brokerID:"test",accountID:"test",tradingDay:this.session.tradingDay,preBalance:1e6,balance:1e6,available:1e6,currMargin:0,frozenMargin:0,frozenCash:0,frozenCommission:0,closeProfit:0,positionProfit:0,commission:0,deposit:0,withdraw:0}]:[];this.push(n.event,{requestID:e,[n.field]:structuredClone(t??this.state[n.field]??i)})}push(e,t){let r={method:e,params:structuredClone(t)};this.trace.record("broker",{operation:"push",message:r});for(let n of this.handlers.get(e)??[])n(structuredClone(r))}on(e,t){let r=this.handlers.get(e)??new Set;return r.add(t),this.handlers.set(e,r),()=>this.off(e,t)}off(e,t){this.handlers.get(e)?.delete(t)}onExit(e){return this.exits.add(e),()=>this.exits.delete(e)}resetClient(){let e=Error("Test gateway client closed");for(let t of this.pending.values())t.cancelTimeout(),t.reject(e);for(let t of this.waiters)t.reject(e);this.pending.clear(),this.waiters.clear(),this.held.clear()}complete(e){let t=this.pending.get(e).request;if(Object.hasOwn(At,t.method))this.completeQuery(e);else this.reply(e)}}class _e{clock;trace;observations;gateway;fixture;transport;instrument;api;adapter;orderRef;orders=new Set;trades=new Set;errors=new Set;reconciled=new Set;faults=new Set;constructor(e,t,r,n,i){this.clock=t;this.trace=r;this.observations=i;this.fixture=e,this.instrument=Ye(e);let o={tradingDay:e.tradingDay,frontID:1,sessionID:1,...n.gatewaySession};this.orderRef=BigInt(o.maxOrderRef??"0"),this.transport=new qr(o,t,r,n.gatewayState);let s=this;this.gateway={get requests(){return structuredClone(s.transport.requests)},pendingRequests:()=>this.transport.pendingRequests(),waitForRequest:(a)=>this.transport.waitForRequest(a),setSnapshot:(a)=>this.transport.setSnapshot(a),hold:(a)=>this.transport.hold(a),resume:(a)=>this.transport.resume(a),reply:(a,d)=>this.transport.reply(a,d),completeQuery:(a,d)=>this.transport.completeQuery(a,d),push:(a,d)=>this.transport.push(a,d),disconnect:()=>this.transport.push("onDisconnected",{}),reconnect:(a)=>this.reconnect(a),queryOrders:()=>this.requireAdapter().queryOrders()}}get phase(){if(this.adapter?.phase==="ready")return"running";return this.adapter?.phase==="faulted"||this.adapter?.phase==="closed"?"faulted":"recovering"}async connect(){if(this.adapter)this.close();this.api=new Rt(this.transport,{clock:{now:()=>this.clock.now,schedule:this.clock.schedule}}),this.api.loginResult=this.transport.session,this.api.connected=!0,this.adapter=new Mt(this.api,{broker:"test",investorId:"test",now:()=>this.clock.now}),this.adapter.registerInstrument(this.instrument),this.adapter.onOrder((e)=>{for(let t of this.orders)t(e)}),this.adapter.onTrade((e)=>{for(let t of this.trades)t(e)}),this.adapter.onOrderError((e)=>{for(let t of this.errors)t(e)}),this.adapter.onReconciled((e)=>{for(let t of this.reconciled)t(e)}),this.adapter.onFault((e)=>{for(let t of this.faults)t(e)}),await this.adapter.initialize(this.transport.session)}close(){this.adapter?.close(),this.api?.dispose(),this.transport.resetClient()}async prepareInstrument(e,t){if(e!==this.instrument.instrumentID||t!==this.instrument.exchangeID)throw Error("Test instrument mismatch");return this.instrument}async prepareCommission(e,t){if(e!==this.instrument.instrumentID||t!==this.instrument.exchangeID)throw Error("Test commission mismatch")}getInstrument(e){return e===this.instrument.instrumentID?this.instrument:null}getCommission(e,t){if(e!==this.instrument.instrumentID||t!==this.instrument.exchangeID)return null;return Ge(this.fixture)}async queryPositions(e){if(this.phase!=="running")return{phase:this.phase,positions:[]};let t=await this.requireAdapter().queryPositions(e);return{phase:this.phase,positions:t}}queryOrders(e){return this.requireAdapter().queryOrders(e)}submitOrder(e){let t=String(++this.orderRef);if(t.length>12)throw Error("CTP OrderRef \u5DF2\u8017\u5C3D\uFF0C\u8BF7\u91CD\u542F\u4EA4\u6613\u4F1A\u8BDD");let r=this.requireAdapter().submitOrder({instrumentID:e.instrumentID,direction:e.direction,offsetFlag:e.offsetFlag,price:e.price,volume:e.volume,exchangeID:this.instrument.exchangeID,orderRef:t,traceId:`vibek:${e.strategyId}:${t}`}),n={vtOrderId:r.vtOrderId,direction:e.direction==="buy"?"long":"short",offset:e.offsetFlag,price:e.price,volume:e.volume};return this.observations.submissions.push(n),this.trace.record("submission",n),r}cancelOrder(e){this.observations.cancelRequests.push(e),this.trace.record("cancel",{vtOrderId:e}),this.requireAdapter().cancelOrder(e)}onOrder(e){return this.orders.add(e),()=>this.orders.delete(e)}onTrade(e){return this.trades.add(e),()=>this.trades.delete(e)}onOrderError(e){return this.errors.add(e),()=>this.errors.delete(e)}onReconciled(e){return this.reconciled.add(e),()=>this.reconciled.delete(e)}onFault(e){return this.faults.add(e),()=>this.faults.delete(e)}reconnect(e={}){let t=this.requireAdapter();return Object.assign(this.transport.session,e),new Promise((r,n)=>{let i=t.onPhase((o)=>{if(o==="ready")i(),r();else if(o==="faulted"||o==="closed")i(),n(Error(`CTP reconciliation ${o}`))});this.transport.push("onDisconnected",{}),this.transport.push("onReconnected",{...this.transport.session})})}requireAdapter(){if(!this.adapter)throw Error("CTP test adapter is not initialized");return this.adapter}}class Bt{fixture;history;now;generate;constructor(e,t,r,n){this.fixture=e;this.history=t;this.now=r;this.generate=n}async getBars(e,t){if(this.history.length===0&&this.generate)this.history.push(...Ii(e,t,this.fixture,this.now));Ie(this.history,this.now,e);let r=ke(this.history,t.timeframe,t.count);if(r.selectedCount!==t.count)throw Error(`\u6D4B\u8BD5\u9884\u70ED\u6570\u636E\u4E0D\u8DB3\uFF1A\u9700\u8981 ${t.count} \u6839 ${t.timeframe}\uFF0C\u4EC5\u6709 ${r.availableCount} \u6839`);return r.bars.map((n)=>({...n}))}destroy(){}}function Ii(e,t,r,n){if(t.count>1e5)throw Error(`\u6D4B\u8BD5\u9884\u70ED\u6570\u636E\u8BF7\u6C42\u8FC7\u5927: ${t.count}`);if(t.timeframe==="1d"){let d=Math.floor(n/60000)*60;return Array.from({length:t.count},(c,u)=>{let l=d-(t.count-u)*86400;return H(r,{code:e,close:r.seedPrice+u*r.priceTick,barTime:l,tradingDay:Ot(l*1000),boundaryReason:"sessionEnd"},u)})}let i=se[t.timeframe]/60,o=t.count*i;if(o>1e5)throw Error(`\u6D4B\u8BD5\u9884\u70ED\u6570\u636E\u8BF7\u6C42\u8FC7\u5927: ${o} \u6839 1min Bar`);let a=Math.floor(n/(i*60000))*i*60-o*60;return Array.from({length:o},(d,c)=>H(r,{code:e,close:r.seedPrice+c*r.priceTick,barTime:a+c*60,tradingDay:Tt(a+c*60)},c))}import{mkdtempSync as Uo,rmSync as jo}from"fs";import{tmpdir as Go}from"os";import{join as Ko}from"path";class Ht{now;tasks=new Map;sequence=0;constructor(e){this.now=e}schedule=(e,t)=>{if(!Number.isSafeInteger(t)||t<0||!Number.isSafeInteger(this.now+t))throw Error("Scheduled delay must be a nonnegative safe integer");let r=++this.sequence;return this.tasks.set(r,{at:this.now+t,callback:e}),()=>{this.tasks.delete(r)}};advanceTo(e,t){if(!Number.isSafeInteger(e)||e<this.now)throw Error("\u6D4B\u8BD5\u65F6\u95F4\u4E0D\u80FD\u56DE\u9000\u6216\u8D85\u8FC7\u5B89\u5168\u6574\u6570\u8303\u56F4");let r=(Math.floor(this.now/1000)+1)*1000,n=0;while(!0){let i=1/0;for(let s of this.tasks.values())i=Math.min(i,s.at);let o=Math.min(i,t?r:1/0);if(o>e)break;if(this.now=o,t&&o===r)t(),r+=1000;for(let[s,a]of this.tasks)if(a.at<=this.now){if(this.tasks.delete(s),++n>1e5)throw Error("Test scheduler exceeded 100000 callbacks in one advance");a.callback()}}this.now=e}}import{AsyncLocalStorage as Di}from"async_hooks";class Lt{now;entries=[];context=new Di;constructor(e){this.now=e}get events(){return this.entries.slice()}close(){this.context.disable()}record(e,t){let r=this.entries.length+1;return this.entries.push(zr({sequence:r,now:this.now(),cause:this.context.getStore()??null,type:e,value:structuredClone(t)})),r}input(e,t){let r=this.record("input",e);return this.context.run(r,()=>{let n=t();if(n instanceof Promise)return n.then((i)=>(this.record("completion",{input:r,status:"fulfilled"}),i),(i)=>{throw this.record("completion",{input:r,status:"rejected",error:i instanceof Error?i.message:String(i)}),i});return n})}bind(e){let t=this.context.getStore()??null;return()=>this.context.run(t,e)}}function zr(e,t=new Set){if(e&&typeof e==="object"){if(t.has(e))return e;t.add(e);for(let r of Object.values(e))zr(r,t);Object.freeze(e)}return e}import{existsSync as ln}from"fs";import{join as I}from"path";import{existsSync as xi,mkdirSync as ba,readFileSync as Ci,renameSync as wa,unlinkSync as Sa,writeFileSync as va}from"fs";import{homedir as Ce}from"os";import{dirname as Pi,isAbsolute as $i,join as C,resolve as zt}from"path";import{isIP as Oi}from"net";function Nt(e){if(e.trim()==="")return[];let t=[],r=new Set,n=e.split(",").map((i)=>i.trim()).filter(Boolean);for(let[i,o]of n.entries()){let s=o.indexOf("@");if(s<=0||s!==o.lastIndexOf("@"))throw Error(`ctp.front_candidates \u7B2C ${i+1} \u9879\u683C\u5F0F\u9519\u8BEF\uFF0C\u5E94\u4E3A \u63CF\u8FF0@IP`);let a=o.slice(0,s).trim(),d=o.slice(s+1).trim();if(a==="")throw Error(`ctp.front_candidates \u7B2C ${i+1} \u9879\u7F3A\u5C11\u7EBF\u8DEF\u63CF\u8FF0`);if(Oi(d)===0)throw Error(`ctp.front_candidates \u7B2C ${i+1} \u9879\u4E0D\u662F\u6709\u6548 IP: ${d||"(\u7A7A)"}`);if(r.has(d))throw Error(`ctp.front_candidates \u5305\u542B\u91CD\u590D IP: ${d}`);r.add(d),t.push({description:a,ip:d})}return t}var xe=[{start:"09:00:00",end:"10:15:00",boundaryReason:"break",acceptsPreOpenTick:!0},{start:"10:30:00",end:"11:30:00",boundaryReason:"break"},{start:"13:30:00",end:"15:00:00",boundaryReason:"sessionEnd"}],Ri=[{start:"09:30:00",end:"11:30:00",boundaryReason:"break",acceptsPreOpenTick:!0},{start:"13:00:00",end:"15:00:00",boundaryReason:"sessionEnd"}],_i=[{start:"09:30:00",end:"11:30:00",boundaryReason:"break",acceptsPreOpenTick:!0},{start:"13:00:00",end:"15:15:00",boundaryReason:"sessionEnd"}];function Ft(e){return[{start:"21:00:00",end:e,boundaryReason:"break",acceptsPreOpenTick:!0},...xe]}var et=Ft("23:00:00"),Ur=Ft("01:00:00"),jr=Ft("02:30:00"),Vt=new Map;function D(e,t,r){for(let n of t){let i=n.toUpperCase();Vt.set(`${e}.${i}`,{exchangeID:e,productID:i,segments:r})}}D("CFFEX",["IF","IH","IC","IM"],Ri);D("CFFEX",["T","TF","TS","TL"],_i);D("SHFE",["AU","AG"],jr);D("SHFE",["CU","AL","ZN","PB","NI","SN","SS","AO","AD"],Ur);D("SHFE",["RB","WR","HC","RU","BU","FU","SP","BR"],et);D("INE",["SC"],jr);D("INE",["BC"],Ur);D("INE",["NR","LU"],et);D("INE",["EC"],xe);D("DCE",["A","B","C","CS","M","Y","P","L","L_F","V","V_F","PP","PP_F","J","JM","I","EG","EB","PG"],et);D("DCE",["JD","FB","BB","RR","LH","LG","BZ"],xe);D("CZCE",["CF","SR","TA","OI","MA","FG","RM","ZC","CY","SA","PF","PX","SH","PR"],et);D("CZCE",["WH","PM","RI","RS","JR","LR","SF","SM","AP","CJ","UR","PK"],xe);D("GFEX",["SI","LC","PS","PT","PD"],xe);function Gr(e,t){return Vt.get(`${e.toUpperCase()}.${t.toUpperCase()}`)??null}function tt(e,t){let r=Gr(e,t);if(!r)throw Error(`\u4EA7\u54C1\u65F6\u6BB5\u76EE\u5F55\u4E0D\u5305\u542B ${t.toUpperCase()}.${e.toUpperCase()}`);return r}function qt(){return[...Vt.values()]}var Mi="VIBEK_CONFIG_PATH",Ai="VIBEK_PROCESS_ACCOUNT",Ut=/^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$/,Kr=["trace","debug","info","warn","error"],Yr=["realtime","replay"];class ee extends Error{path;diagnostics;constructor(e,t){super(`\u914D\u7F6E\u6587\u4EF6\u65E0\u6548: ${e}
3
3
  ${t.map((r)=>` - ${r}`).join(`
4
- `)}`);this.path=e;this.diagnostics=t;this.name="ConfigValidationError"}}class Qr{errors=[];table(e,t){if(Bi(e))return e;return this.errors.push(`${t} \u5FC5\u987B\u662F TOML \u8868`),{}}keys(e,t,r){let n=new Set(t);for(let i of Object.keys(e))if(!n.has(i))this.errors.push(`\u672A\u77E5\u914D\u7F6E\u9879 ${r?`${r}.`:""}${i}`)}string(e,t,r,n={}){let i=e[t],o=`${r}.${t}`;if(i===void 0){if(n.required)this.errors.push(`\u7F3A\u5C11\u914D\u7F6E\u9879 ${o}`);return}if(typeof i!=="string"){this.errors.push(`${o} \u5FC5\u987B\u662F\u5B57\u7B26\u4E32`);return}if(n.nonEmpty&&i.trim()===""){this.errors.push(`${o} \u4E0D\u80FD\u4E3A\u7A7A`);return}return i}boolean(e,t,r){let n=e[t];if(n===void 0)return;if(typeof n!=="boolean"){this.errors.push(`${r}.${t} \u5FC5\u987B\u662F\u5E03\u5C14\u503C`);return}return n}integer(e,t,r,n,i){let o=e[t];if(o===void 0)return;if(!Number.isInteger(o)||o<n||o>i){this.errors.push(`${r}.${t} \u5FC5\u987B\u662F ${n}..${i} \u7684\u6574\u6570`);return}return o}strings(e,t,r){let n=e[t];if(n===void 0)return;if(!Array.isArray(n)||n.some((i)=>typeof i!=="string")){this.errors.push(`${r}.${t} \u5FC5\u987B\u662F\u5B57\u7B26\u4E32\u6570\u7EC4`);return}return[...n]}}function Bi(e){return typeof e==="object"&&e!==null&&!Array.isArray(e)}function j(e,t,r,n=""){let i=t[r];if(i===void 0)return;return e.table(i,n?`${n}.${r}`:r)}function rt(e,t,r){if(e!==void 0&&!/^([01]\d|2[0-3]):[0-5]\d$/.test(e))r.push(`${t} \u5FC5\u987B\u4F7F\u7528 HH:MM\uFF0824 \u5C0F\u65F6\uFF09\u683C\u5F0F`)}function Wr(e,t,r){if(e===void 0)return;try{let n=new URL(e),i=Number(n.port);if(n.protocol!=="tcp:"||!n.hostname||!Number.isInteger(i)||i<1||i>65535)throw Error("invalid")}catch{r.push(`${t} \u5FC5\u987B\u662F tcp://host:port`)}}var Jr=/^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$/;function Hi(e,t){if(t===void 0)return;let r="account.timer_hooks";if(!Array.isArray(t))return e.errors.push(`${r} \u5FC5\u987B\u662F TOML \u8868\u6570\u7EC4`),[];let n=[],i=new Set;for(let[o,s]of t.entries()){let a=`${r}[${o}]`,d=e.table(s,a);e.keys(d,["name","cron","timezone","enabled"],a);let c=e.string(d,"name",a,{required:!0,nonEmpty:!0}),u=e.string(d,"cron",a,{required:!0,nonEmpty:!0}),l=e.string(d,"timezone",a,{required:!0,nonEmpty:!0}),f=e.boolean(d,"enabled",a);if(c!==void 0)if(!Jr.test(c))e.errors.push(`${a}.name \u5FC5\u987B\u5339\u914D ${Jr.source}`);else if(i.has(c))e.errors.push(`${r} \u4E0D\u5141\u8BB8\u91CD\u590D\u540D\u79F0: ${c}`);else i.add(c);let h=u?.trim().replace(/\s+/g," "),m=l?.trim(),v=!1;if(m)try{Bun.cron.parse("0 0 * * *",Date.now(),{tz:m}),v=!0}catch{e.errors.push(`${a}.timezone \u4E0D\u662F\u6709\u6548\u7684 IANA \u65F6\u533A`)}if(h!==void 0&&h.split(" ").length!==5)e.errors.push(`${a}.cron \u5FC5\u987B\u662F 5 \u6BB5 cron \u8868\u8FBE\u5F0F`);else if(h!==void 0&&v)try{if(Bun.cron.parse(h,Date.now(),{tz:m})===null)e.errors.push(`${a}.cron \u5728\u672A\u6765 8 \u5E74\u5185\u6CA1\u6709\u89E6\u53D1\u65F6\u95F4`)}catch{e.errors.push(`${a}.cron \u4E0D\u662F\u6709\u6548\u7684 cron \u8868\u8FBE\u5F0F`)}if(c!==void 0&&h!==void 0&&m!==void 0)n.push({name:c,cron:h,timezone:m,...f===void 0?{}:{enabled:f}})}return n}var Zr=new Set(["CFFEX","SHFE","CZCE","DCE","INE","GFEX"]);function Li(e){let t=e.trim(),r=/^([A-Za-z][A-Za-z0-9]*)\.([A-Za-z]+)$/.exec(t),n=r??/^([A-Za-z][A-Za-z0-9]*)$/.exec(t);if(!n||!/\d/.test(n[1]))throw Error(`\u5408\u7EA6 ${JSON.stringify(e)} \u975E\u6CD5\uFF0C\u5E94\u4F7F\u7528 CODE \u6216 CODE.EXCHANGE`);let i=n[1].toUpperCase(),o=Ni(i),s=r?n[2].toUpperCase():o;if(!s||!Zr.has(s)){if(r)throw Error(`\u5408\u7EA6\u4EA4\u6613\u6240\u975E\u6CD5: ${e}`);throw Error(`\u65E0\u6CD5\u63A8\u65AD\u5408\u7EA6 ${i} \u7684\u4EA4\u6613\u6240\uFF0C\u8BF7\u4F7F\u7528 ${i}.EXCHANGE`)}if(r&&o&&o!==s)throw Error(`\u5408\u7EA6 ${i} \u5E94\u4F7F\u7528\u4EA4\u6613\u6240 ${o}\uFF0C\u800C\u4E0D\u662F ${s}`);return{instrumentID:i,exchangeID:s,vtSymbol:`${i}.${s}`}}function Ni(e){let t=/^[A-Z]+/.exec(e)?.[0];if(!t)return null;let r=new Set;for(let n of Vt())if((n.productID.endsWith("_F")?n.productID.slice(0,-2):n.productID)===t)r.add(n.exchangeID);return r.size===1?[...r][0]:null}function jt(e){let t=[],r=new Map;for(let n of e){let i=n.trim(),o=/^([A-Za-z][A-Za-z0-9]*)\.([A-Za-z]+)$/.exec(i);if(!o||!/\d/.test(o[1]))throw Error(`market.record_instruments \u9879 ${JSON.stringify(n)} \u975E\u6CD5\uFF0C\u5E94\u4F7F\u7528 CODE.EXCHANGE`);let s=o[1].toUpperCase(),a=o[2].toUpperCase();if(!Zr.has(a))throw Error(`market.record_instruments \u4EA4\u6613\u6240\u975E\u6CD5: ${n}`);let d=r.get(s);if(d&&d!==a)throw Error(`market.record_instruments \u5408\u7EA6\u4EA4\u6613\u6240\u51B2\u7A81: ${s}.${d} / ${s}.${a}`);if(d)continue;r.set(s,a),t.push({instrumentID:s,exchangeID:a,vtSymbol:`${s}.${a}`})}return t}function Fi(e,t){let r=new Set(e.map((i)=>i.vtSymbol)),n=[...new Set(t.filter((i)=>!r.has(i.vtSymbol)).map((i)=>i.vtSymbol))];if(n.length>0)throw Error(`account.market.bar_hooks \u4F7F\u7528\u4E86\u672A\u5F55\u5236\u8BA2\u9605\u7684\u5408\u7EA6: ${n.join(", ")}`)}function nt(e,t){let r=[],n=new Set;for(let[i,o]of e.entries()){let s;try{s=Li(o.instrument)}catch(d){throw Error(`account.market.bar_hooks[${i}].instrument: ${d instanceof Error?d.message:String(d)}`)}if(!Z(o.timeframe))throw Error(`account.market.bar_hooks[${i}].timeframe \u5FC5\u987B\u662F ${ve}`);let a=`${s.vtSymbol}/${o.timeframe}`;if(n.has(a))throw Error(`account.market.bar_hooks \u4E0D\u5141\u8BB8\u91CD\u590D\u7EC4\u5408: ${a}`);n.add(a),r.push({...s,timeframe:o.timeframe})}return Fi(t,r),r}function Gt(e,t){let r=e?.trim()??"",n=t?.trim()??"";if(!r||!n)return"";let i=`${r}-${n}`;return Ut.test(i)?i:""}function qi(e,t){let n=e.table(t,"account");e.keys(n,["broker_id","user","ctp","timer_hooks","logging","market","reference_data","trading","schedule"],"account");let i=e.string(n,"broker_id","account",{required:!0,nonEmpty:!0})??"",o=e.string(n,"user","account",{required:!0,nonEmpty:!0})??"";if(!Gt(i,o)&&i&&o)e.errors.push(`${"account"}.broker_id \u4E0E ${"account"}.user \u65E0\u6CD5\u7EC4\u6210\u5408\u6CD5\u8D26\u53F7\u540D`);let a=e.table(n.ctp,"account.ctp");e.keys(a,["market_front","trader_front","front_candidates","password","app_id","auth_code","production_mode"],"account.ctp");let d=e.string(a,"market_front","account.ctp",{required:!0,nonEmpty:!0})??"",c=e.string(a,"trader_front","account.ctp",{required:!0,nonEmpty:!0})??"",u=e.strings(a,"front_candidates","account.ctp"),l=e.string(a,"password","account.ctp"),f=e.string(a,"app_id","account.ctp",{required:!0,nonEmpty:!0})??"",h=e.string(a,"auth_code","account.ctp",{required:!0,nonEmpty:!0})??"",m=e.boolean(a,"production_mode","account.ctp");if(Wr(d||void 0,"account.ctp.market_front",e.errors),Wr(c||void 0,"account.ctp.trader_front",e.errors),u)try{Nt(u.join(","))}catch(S){e.errors.push(`account.ctp.front_candidates: ${S instanceof Error?S.message:String(S)}`)}let v=Hi(e,n.timer_hooks),p=j(e,n,"logging","account");if(p){e.keys(p,["level"],"account.logging");let S=e.string(p,"level","account.logging");if(S!==void 0&&!Kr.includes(S))e.errors.push(`${"account"}.logging.level \u5FC5\u987B\u662F ${Kr.join(" | ")}`)}let k=j(e,n,"market","account");if(k){e.keys(k,["db_path","record_instruments","bar_hooks","tick_time_mode","max_future_tick_ms"],"account.market"),e.string(k,"db_path","account.market");let S=e.strings(k,"record_instruments","account.market"),z=k.bar_hooks,oe=[];if(z!==void 0)if(!Array.isArray(z))e.errors.push(`${"account"}.market.bar_hooks \u5FC5\u987B\u662F TOML \u8868\u6570\u7EC4`);else for(let[A,Zn]of z.entries()){let be=`account.market.bar_hooks[${A}]`,bt=e.table(Zn,be);e.keys(bt,["instrument","timeframe"],be);let yr=e.string(bt,"instrument",be,{required:!0,nonEmpty:!0}),Fe=e.string(bt,"timeframe",be,{required:!0});if(yr!==void 0&&Z(Fe))oe.push({instrument:yr,timeframe:Fe});else if(Fe!==void 0&&!Z(Fe))e.errors.push(`${be}.timeframe \u5FC5\u987B\u662F ${ve}`)}let Ne=e.string(k,"tick_time_mode","account.market");if(Ne!==void 0&&!Yr.includes(Ne))e.errors.push(`${"account"}.market.tick_time_mode \u5FC5\u987B\u662F ${Yr.join(" | ")}`);if(e.integer(k,"max_future_tick_ms","account.market",0,2592000000),S)try{let A=jt(S);nt(oe,A)}catch(A){e.errors.push(A instanceof Error?A.message:String(A))}else if(oe.length>0)try{nt(oe,[])}catch(A){e.errors.push(A instanceof Error?A.message:String(A))}}let V=j(e,n,"reference_data","account");if(V)e.keys(V,["contracts_path","commissions_path"],"account.reference_data"),e.string(V,"contracts_path","account.reference_data"),e.string(V,"commissions_path","account.reference_data");let M=j(e,n,"trading","account");if(M){e.keys(M,["max_order_volume","max_position","max_active_open_orders","daily_limits","duplicate_orders"],"account.trading"),e.integer(M,"max_order_volume","account.trading",1,1e4),e.integer(M,"max_position","account.trading",1,1e5),e.integer(M,"max_active_open_orders","account.trading",1,1000);let S=j(e,M,"daily_limits","account.trading");if(S)e.keys(S,["total_order_limit","total_cancel_limit","total_trade_limit","instrument_order_limit","instrument_cancel_limit","instrument_trade_limit"],"account.trading.daily_limits"),e.integer(S,"total_order_limit","account.trading.daily_limits",1,1e7),e.integer(S,"total_cancel_limit","account.trading.daily_limits",1,1e7),e.integer(S,"total_trade_limit","account.trading.daily_limits",1,1e7),e.integer(S,"instrument_order_limit","account.trading.daily_limits",1,1e7),e.integer(S,"instrument_cancel_limit","account.trading.daily_limits",1,1e7),e.integer(S,"instrument_trade_limit","account.trading.daily_limits",1,1e7);let z=j(e,M,"duplicate_orders","account.trading");if(z)e.keys(z,["duplicate_order_limit"],"account.trading.duplicate_orders"),e.integer(z,"duplicate_order_limit","account.trading.duplicate_orders",2,1000)}let R=j(e,n,"schedule","account");if(R){e.keys(R,["enabled","day_start","day_stop","night_start","night_stop","max_start_attempts","retry_base_ms","tick_ms"],"account.schedule"),e.boolean(R,"enabled","account.schedule");let S=e.string(R,"day_start","account.schedule"),z=e.string(R,"day_stop","account.schedule"),oe=e.string(R,"night_start","account.schedule"),Ne=e.string(R,"night_stop","account.schedule");rt(S,"account.schedule.day_start",e.errors),rt(z,"account.schedule.day_stop",e.errors),rt(oe,"account.schedule.night_start",e.errors),rt(Ne,"account.schedule.night_stop",e.errors),e.integer(R,"max_start_attempts","account.schedule",1,10),e.integer(R,"retry_base_ms","account.schedule",5000,600000),e.integer(R,"tick_ms","account.schedule",5000,120000)}return{identity:{broker_id:i,user:o},ctp:{market_front:d,trader_front:c,...u===void 0?{}:{front_candidates:u},...l===void 0?{}:{password:l},app_id:f,auth_code:h,...m===void 0?{}:{production_mode:m}},...v===void 0?{}:{timer_hooks:v},...p===void 0?{}:{logging:p},...k===void 0?{}:{market:k},...V===void 0?{}:{reference_data:V},...M===void 0?{}:{trading:M},...R===void 0?{}:{schedule:R}}}function Vi(e,t=F()){let r=new Qr,n=r.table(e,"config");r.keys(n,["account","storage","server"],"");let i=j(r,n,"storage");if(i)r.keys(i,["data_root"],"storage"),r.string(i,"data_root","storage",{nonEmpty:!0});let o=j(r,n,"server");if(o){r.keys(o,["daemon_port","webui_port"],"server");let l=r.integer(o,"daemon_port","server",1,65535),f=r.integer(o,"webui_port","server",1,65535);if(l!==void 0&&l===f)r.errors.push("server.daemon_port \u4E0E server.webui_port \u4E0D\u80FD\u76F8\u540C")}let s=n.account,a=s===void 0?void 0:qi(r,s),d=a?.reference_data?.contracts_path?.trim(),c=a?.reference_data?.commissions_path?.trim(),u=a?Gt(a.identity.broker_id,a.identity.user):"";if(a&&u){let l={account:a,...i===void 0?{}:{storage:i}},f=C(le(l,t),"accounts",u),h=d?W(d,t):C(f,"contracts.jsonl"),m=c?W(c,t):C(f,"commissions.jsonl");if(h===m)r.errors.push("account.reference_data.contracts_path \u4E0E commissions_path \u4E0D\u80FD\u6307\u5411\u540C\u4E00\u6587\u4EF6")}if(r.errors.length>0)throw new ee(t,r.errors);return{...a===void 0?{}:{account:a},...i===void 0?{}:{storage:i},...o===void 0?{}:{server:o}}}function zi(e,t=F()){let r;try{r=Bun.TOML.parse(e)}catch(n){throw new ee(t,[`TOML \u8BED\u6CD5\u9519\u8BEF: ${n instanceof Error?n.message:String(n)}`])}return Vi(r,t)}function F(){let e=process.env[Mi]?.trim();if(e)return zt(e);if(process.platform==="win32"){let t=process.env.APPDATA??(process.env.USERPROFILE?C(process.env.USERPROFILE,"AppData","Roaming"):C(Ce(),"AppData","Roaming"));return C(t,"vibek","config.toml")}return C(process.env.XDG_CONFIG_HOME??C(Ce(),".config"),"vibek","config.toml")}function Ui(e=F()){if(!_i(e))return{path:e,exists:!1,file:{},errors:[]};try{return{path:e,exists:!0,file:zi(Ci(e,"utf8"),e),errors:[]}}catch(t){if(t instanceof ee)return{path:e,exists:!0,file:null,errors:[...t.diagnostics]};return{path:e,exists:!0,file:null,errors:[t instanceof Error?t.message:String(t)]}}}function ue(e=F()){let t=Ui(e);if(t.errors.length>0||t.file===null)throw new ee(e,t.errors);return t.file}function Xr(e=ue()){let t=Gt(e.account?.identity.broker_id,e.account?.identity.user),r=process.env[Ai]?.trim();if(r){if(r!==t)throw new ee(F(),[`\u5185\u90E8\u8FDB\u7A0B\u8D26\u53F7 ${JSON.stringify(r)} \u4E0E\u5F53\u524D\u914D\u7F6E ${JSON.stringify(t)} \u4E0D\u4E00\u81F4`]);return{name:r,source:"process"}}return t?{name:t,source:"config"}:{name:"",source:"none"}}function W(e,t=F()){let r=e==="~"?Ce():e.startsWith("~/")||e.startsWith("~\\")?C(Ce(),e.slice(2)):e;return $i(r)?zt(r):zt(Pi(t),r)}function le(e=ue(),t=F()){return W(e.storage?.data_root??C(Ce(),".vibek"),t)}function ji(e=ue()){return C(le(e),"accounts")}function en(e,t=ue()){if(!Ut.test(e))throw Error(`\u8D26\u53F7\u540D\u975E\u6CD5: ${e}`);return C(ji(t),e)}import{existsSync as tn,readFileSync as Gi}from"fs";import{isAbsolute as Ki,join as rn,relative as Yi,resolve as Wi}from"path";var Ji=1;function Pe(e=le()){return rn(e,"gateway")}function Qi(e=Pe()){return rn(e,"current.json")}function nn(e=Pe(),t={}){let r=Qi(e);if(!tn(r))return null;try{let n=JSON.parse(Gi(r,"utf8")),i=Zi(n),o=t.platform??process.platform,s=t.arch??process.arch;if(i.platform!==o||i.arch!==s)throw Error(`\u5E73\u53F0\u4E0D\u5339\u914D: ${i.platform}-${i.arch} / ${o}-${s}`);let a=Kt(e,i);if(t.requireExecutable!==!1&&!tn(a))throw Error(`executable \u4E0D\u5B58\u5728: ${a}`);return i}catch(n){if(t.tolerateInvalid)return null;throw Error(`\u53D7\u7BA1 gateway \u72B6\u6001\u65E0\u6548: ${r}: ${n instanceof Error?n.message:String(n)}`)}}function Kt(e,t){let r=Wi(e,t.relativeExecutable),n=Yi(e,r);if(!n||n.startsWith("..")||Ki(n))throw Error("relativeExecutable \u8D8A\u51FA\u53D7\u7BA1 gateway \u76EE\u5F55");return r}function Zi(e){if(!e||typeof e!=="object"||Array.isArray(e))throw Error("\u5FC5\u987B\u662F JSON \u5BF9\u8C61");let t=e,r=t.source;if(!r||typeof r!=="object"||Array.isArray(r))throw Error("source \u5FC5\u987B\u662F JSON \u5BF9\u8C61");let n=r;if(n.kind!=="official"&&n.kind!=="local")throw Error("source.kind \u975E\u6CD5");let i=["releaseKey","gatewayVersion","ctpSdkVersion","platform","arch","relativeExecutable","contentSha256","installedAt"];for(let o of i)if(typeof t[o]!=="string"||!t[o].trim())throw Error(`${o} \u975E\u6CD5`);if(t.formatVersion!==Ji)throw Error("formatVersion \u4E0D\u517C\u5BB9");if(!Number.isInteger(t.protocolVersion)||t.protocolVersion<1)throw Error("protocolVersion \u975E\u6CD5");if(!/^[a-f0-9]{64}$/.test(t.contentSha256))throw Error("contentSha256 \u975E\u6CD5");if(t.archiveSha256!==void 0&&!/^[a-f0-9]{64}$/.test(String(t.archiveSha256)))throw Error("archiveSha256 \u975E\u6CD5");if(typeof n.reference!=="string"||!n.reference)throw Error("source.reference \u975E\u6CD5");return t}import{existsSync as an,realpathSync as Xi}from"fs";import{dirname as eo,join as dn,resolve as on}from"path";var sn=process.platform==="win32"?"ctp_gateway.exe":"ctp_gateway",it=import.meta.dir,cn=it;try{cn=eo(Xi(Bun.main))}catch{}var to="vibek-package.json";function ro(e){return[...new Set(e)].find((t)=>an(dn(t,to)))??""}var ot=ro([cn,it]);var Yt=[on(it,"..","..","ctp-gateway","build","bin","Debug",sn),on(it,"..","..","..","..","ctp-gateway","build","bin","Debug",sn)];function no(e=process.platform){let t=e==="win32"?"ctp_gateway.exe":"ctp_gateway";return e==="linux"?"/opt/vibek-gateway/current/ctp_gateway":e==="darwin"?"/usr/local/lib/vibek-gateway/current/ctp_gateway":dn(process.env.ProgramData??"C:\\ProgramData","Vibek","gateway","current",t)}var un=Yt.find((e)=>an(e))??(ot?no():Yt[Yt.length-1]);var te=ue(),Wt=process.env.VIBEK_PROCESS_ROLE??"",at=Wt==="webui"||Wt==="hooks"?{name:"",source:"none"}:Xr(te),g=at.name?te.account:void 0,mn=g?.ctp.production_mode??!0,hn=g?.ctp.password??"",io=hn.trim().length>0,Jt=jt(g?.market?.record_instruments??[]),oo=nt(g?.market?.bar_hooks??[],Jt),P=le(te),pn=I(P,"hooks"),me=at.name?en(at.name,te):I(P,"accounts",".unresolved"),so=I(me,"vibek_bars.db"),ao=I(me,"contracts.jsonl"),co=I(me,"commissions.jsonl"),gn=ot?nn(Pe(P),{requireExecutable:!0}):null,uo=gn?Kt(Pe(P),gn):un;function st(e){let t=/^([01]\d|2[0-3]):([0-5]\d)$/.exec(e);return{minutes:Number(t[1])*60+Number(t[2]),label:e}}var re={processRole:Wt,account:at.name,packageRoot:ot,broker:g?.identity.broker_id??"",user:g?.identity.user??"",pass:g?io?hn:process.env.VIBEK_PASS||"":"",addr:g?.ctp.market_front??"",traderAddr:g?.ctp.trader_front??"",ctpFronts:g?.ctp.front_candidates?.join(",")??"",ctpProductionMode:mn,authCode:g?.ctp.auth_code??"",appId:g?.ctp.app_id??"",logLevel:g?.logging?.level??(mn?"info":"debug"),daemonPort:te.server?.daemon_port??3111,daemonHttpUrl:`http://127.0.0.1:${te.server?.daemon_port??3111}`,webui:{port:te.server?.webui_port??3211},gatewayPath:uo,timerHooks:(g?.timer_hooks??[]).map((e)=>({name:e.name,cron:e.cron,timezone:e.timezone,enabled:e.enabled??!0})),market:{instruments:Jt.map((e)=>e.instrumentID),declarations:Jt,barHooks:oo,tickTimeMode:g?.market?.tick_time_mode??"realtime",maxFutureTickMs:g?.market?.max_future_tick_ms??5000,testFlush:process.env.VIBEK_TEST_FLUSH!==void 0},trading:{maxOrderVolume:g?.trading?.max_order_volume??10,maxPosition:g?.trading?.max_position??20,maxActiveOpenOrders:g?.trading?.max_active_open_orders??5,dailyLimits:{totalOrderLimit:g?.trading?.daily_limits?.total_order_limit??20000,totalCancelLimit:g?.trading?.daily_limits?.total_cancel_limit??1e4,totalTradeLimit:g?.trading?.daily_limits?.total_trade_limit??1e4,instrumentOrderLimit:g?.trading?.daily_limits?.instrument_order_limit??2000,instrumentCancelLimit:g?.trading?.daily_limits?.instrument_cancel_limit??1000,instrumentTradeLimit:g?.trading?.daily_limits?.instrument_trade_limit??1000},duplicateOrders:{duplicateOrderLimit:g?.trading?.duplicate_orders?.duplicate_order_limit??10}},schedule:{enabled:g?.schedule?.enabled??!0,dayStart:st(g?.schedule?.day_start??"08:45"),dayStop:st(g?.schedule?.day_stop??"15:15"),nightStart:st(g?.schedule?.night_start??"20:45"),nightStop:st(g?.schedule?.night_stop??"02:35"),maxStartAttempts:g?.schedule?.max_start_attempts??4,retryBaseMs:g?.schedule?.retry_base_ms??30000,tickMs:g?.schedule?.tick_ms??30000}},pe={config:F(),root:P,accounts:I(P,"accounts"),ai:I(P,"ai"),aiWorkspace:ln(I(P,"ai-workspace"))||!ln(I(P,"tui-workspace"))?I(P,"ai-workspace"):I(P,"tui-workspace"),hooks:pn,hooksSocket:I(P,"run","hooks.sock"),hookHostsDb:I(pn,"hosts.sqlite"),data:me,logs:I(me,"logs"),gatewayWorkdir:I(me,"gateway"),db:g?.market?.db_path?W(g.market.db_path):so,contracts:g?.reference_data?.contracts_path?.trim()?W(g.reference_data.contracts_path):ao,commissions:g?.reference_data?.commissions_path?.trim()?W(g.reference_data.commissions_path):co};var dt=30000;var od=Number.MAX_VALUE/2;import{randomUUID as No}from"crypto";var ct=/^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$/,lo=/^[A-Z][A-Z0-9]*\.[A-Z]+$/,ut=/^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$/;function O(e){return typeof e==="object"&&e!==null&&!Array.isArray(e)}function mo(e,t){let r=new Set(t);return Object.keys(e).every((n)=>r.has(n))}function y(e,t){return mo(e,t)&&t.every((r)=>Object.hasOwn(e,r))}function q(e,t=4096){return typeof e==="string"&&e.length>0&&e.length<=t}function ge(e){return typeof e==="string"&&lo.test(e)&&/\d/.test(e.split(".")[0]??"")}function lt(e){if(typeof e!=="string"||!/^\d{8}$/.test(e))return!1;let t=Number(e.slice(0,4)),r=Number(e.slice(4,6)),n=Number(e.slice(6,8)),i=new Date(Date.UTC(t,r-1,n));return i.getUTCFullYear()===t&&i.getUTCMonth()===r-1&&i.getUTCDate()===n}function Qt(e,t,r=new Set){if(e===null||typeof e==="string"||typeof e==="boolean")return e;if(typeof e==="number"){if(!Number.isFinite(e))throw Error(`${t} contains a non-finite number`);return e}if(typeof e!=="object")throw Error(`${t} is not JSON`);if(r.has(e))throw Error(`${t} contains a cycle`);r.add(e);try{if(Array.isArray(e)){let i=[];for(let o=0;o<e.length;o++){if(!Object.hasOwn(e,o))throw Error(`${t}[${o}] is not JSON`);i.push(Qt(e[o],`${t}[${o}]`,r))}return i}let n=Object.getPrototypeOf(e);if(n!==Object.prototype&&n!==null)throw Error(`${t} is not a plain object`);return Object.fromEntries(Object.entries(e).map(([i,o])=>[i,Qt(o,`${t}.${i}`,r)]))}finally{r.delete(e)}}function fn(e,t){if(!O(e))throw Error(`${t} is not JSON`);let r=Qt(e,t);if(!O(r))throw Error(`${t} is not JSON`);return r}function yn(e,t){if(!O(t))throw Error(`invalid payload for ${e}`);if(e==="daemon.ready"){if(y(t,[]))return{}}else if(e==="daemon.stopping"){if(y(t,["signal"])&&(t.signal==="API"||t.signal==="SIGINT"||t.signal==="SIGTERM"))return{signal:t.signal}}else if(e==="daemon.service.faulted"){if(y(t,["service","reason"])&&(t.service==="market"||t.service==="trading")&&typeof t.reason==="string"&&t.reason.length>0&&t.reason.length<=4096)return{service:t.service,reason:t.reason}}else if(y(t,["service"])&&(t.service==="market"||t.service==="trading"))return{service:t.service};throw Error(`invalid payload for ${e}`)}var bn=["1min","3min","5min","10min","15min","30min","1h","2h","4h","1d"];function Zt(e){return typeof e==="string"&&bn.includes(e)}function wn(e,t){let r=["vtSymbol","timeframe","barTime","open","high","low","close","volume","tradingDay"];if(typeof t!=="object"||t===null||Array.isArray(t))throw Error(`invalid payload for ${e}`);let n=t,i=y(n,r)||y(n,[...r,"boundaryReason"]),o=[n.open,n.high,n.low,n.close,n.volume];if(!i||!ge(n.vtSymbol)||!Zt(n.timeframe)||!Number.isSafeInteger(n.barTime)||Number(n.barTime)<0||!o.every((s)=>typeof s==="number"&&Number.isFinite(s))||Number(n.volume)<0||n.tradingDay!==null&&!lt(n.tradingDay)||n.boundaryReason!==void 0&&n.boundaryReason!=="break"&&n.boundaryReason!=="sessionEnd"&&n.boundaryReason!=="disconnect")throw Error(`invalid payload for ${e}`);return{vtSymbol:n.vtSymbol,timeframe:n.timeframe,barTime:n.barTime,open:n.open,high:n.high,low:n.low,close:n.close,volume:n.volume,tradingDay:n.tradingDay,...n.boundaryReason===void 0?{}:{boundaryReason:n.boundaryReason}}}var Sn=["strategy","manual"],vn=["max_order_volume","max_position","max_active_open_orders","trading_day_unresolved","trading_day_mismatch","daily_total_order_limit","daily_total_cancel_limit","daily_total_trade_limit","daily_instrument_order_limit","daily_instrument_cancel_limit","daily_instrument_trade_limit","duplicate_order_limit"];function kn(e,t){if(e!=="risk.order_rejected"||!O(t)||!y(t,["source","riskCode","mode","vtSymbol","tradingDay","direction","offset","price","volume","reason"].concat(Object.hasOwn(t,"strategyId")?["strategyId"]:[]))||!Sn.includes(t.source)||!vn.includes(t.riskCode)||t.mode!=="paper"&&t.mode!=="live"||!ge(t.vtSymbol)||t.tradingDay!==null&&!lt(t.tradingDay)||t.direction!=="long"&&t.direction!=="short"||!["open","close","closeToday","closeYesterday"].includes(String(t.offset))||typeof t.price!=="number"||!Number.isFinite(t.price)||t.price<=0||!Number.isSafeInteger(t.volume)||Number(t.volume)<=0||!q(t.reason)||Object.hasOwn(t,"strategyId")&&(typeof t.strategyId!=="string"||!ct.test(t.strategyId)))throw Error(`invalid payload for ${e}`);return{source:t.source,riskCode:t.riskCode,mode:t.mode,vtSymbol:t.vtSymbol,tradingDay:t.tradingDay,direction:t.direction,offset:t.offset,price:t.price,volume:t.volume,reason:t.reason,...typeof t.strategyId==="string"?{strategyId:t.strategyId}:{}}}var Tn=["window","windowId"];function po(e){return(e.window==="day"||e.window==="night")&&q(e.windowId,128)&&e.windowId.endsWith(`/${e.window}`)}function En(e,t){if(!O(t)||!po(t))throw Error(`invalid payload for ${e}`);let r={window:t.window,windowId:t.windowId};if(e==="schedule.window.opened"||e==="schedule.window.closed"){if(y(t,Tn))return r}else if(y(t,[...Tn,"attempts","reason"])&&Number.isSafeInteger(t.attempts)&&Number(t.attempts)>0&&q(t.reason))return{...r,attempts:t.attempts,reason:t.reason};throw Error(`invalid payload for ${e}`)}var he=["strategyId","mode","vtSymbol"];function go(e){return typeof e.strategyId==="string"&&ct.test(e.strategyId)&&(e.mode==="paper"||e.mode==="live")&&ge(e.vtSymbol)}function ho(e){return{strategyId:e.strategyId,mode:e.mode,vtSymbol:e.vtSymbol}}function In(e,t){if(!O(t)||!go(t))throw Error(`invalid payload for ${e}`);let r=ho(t);switch(e){case"strategy.loaded":if(!y(t,[...he,"replaced"])||typeof t.replaced!=="boolean")break;return{...r,replaced:t.replaced};case"strategy.unloaded":case"strategy.enabled":case"strategy.disabled":case"strategy.started":case"strategy.stopped":if(!y(t,he))break;return r;case"strategy.start_failed":if(!y(t,[...he,"reason"])||!q(t.reason))break;return{...r,reason:t.reason};case"strategy.orders_retained":if(!y(t,[...he,"activeOrders","reason"])||!Number.isSafeInteger(t.activeOrders)||Number(t.activeOrders)<=0||!q(t.reason))break;return{...r,activeOrders:t.activeOrders,reason:t.reason};case"strategy.faulted":if(!y(t,[...he,"callback","reason"])||!q(t.callback,128)||!q(t.reason))break;return{...r,callback:t.callback,reason:t.reason};case"strategy.event":{if(!y(t,[...he,"name","data"])||typeof t.name!=="string"||!ut.test(t.name))break;let n=fn(t.data,"strategy.event.data");return{...r,name:t.name,data:n}}}throw Error(`invalid payload for ${e}`)}function Dn(e,t){if(!O(t)||!y(t,["name"])||typeof t.name!=="string"||!ut.test(t.name))throw Error(`invalid payload for ${e}`);return{name:t.name}}var Xt=65536;function er(e,t){if(e.startsWith("risk."))return kn(e,t);if(e.startsWith("strategy."))return In(e,t);if(e.startsWith("timer."))return Dn(e,t);if(e.startsWith("schedule."))return En(e,t);if(e.startsWith("market."))return wn(e,t);return yn(e,t)}function fe(e){let t=new TextEncoder().encode(JSON.stringify(e));if(t.byteLength>Xt)throw Error(`hook frame exceeds ${Xt} bytes`);let r=new Uint8Array(4+t.byteLength);return new DataView(r.buffer).setUint32(0,t.byteLength,!1),r.set(t,4),r}import{Database as So}from"bun:sqlite";function Rn(e){e.run("PRAGMA journal_mode=WAL"),e.run(`
4
+ `)}`);this.path=e;this.diagnostics=t;this.name="ConfigValidationError"}}class Qr{errors=[];table(e,t){if(Bi(e))return e;return this.errors.push(`${t} \u5FC5\u987B\u662F TOML \u8868`),{}}keys(e,t,r){let n=new Set(t);for(let i of Object.keys(e))if(!n.has(i))this.errors.push(`\u672A\u77E5\u914D\u7F6E\u9879 ${r?`${r}.`:""}${i}`)}string(e,t,r,n={}){let i=e[t],o=`${r}.${t}`;if(i===void 0){if(n.required)this.errors.push(`\u7F3A\u5C11\u914D\u7F6E\u9879 ${o}`);return}if(typeof i!=="string"){this.errors.push(`${o} \u5FC5\u987B\u662F\u5B57\u7B26\u4E32`);return}if(n.nonEmpty&&i.trim()===""){this.errors.push(`${o} \u4E0D\u80FD\u4E3A\u7A7A`);return}return i}boolean(e,t,r){let n=e[t];if(n===void 0)return;if(typeof n!=="boolean"){this.errors.push(`${r}.${t} \u5FC5\u987B\u662F\u5E03\u5C14\u503C`);return}return n}integer(e,t,r,n,i){let o=e[t];if(o===void 0)return;if(!Number.isInteger(o)||o<n||o>i){this.errors.push(`${r}.${t} \u5FC5\u987B\u662F ${n}..${i} \u7684\u6574\u6570`);return}return o}strings(e,t,r){let n=e[t];if(n===void 0)return;if(!Array.isArray(n)||n.some((i)=>typeof i!=="string")){this.errors.push(`${r}.${t} \u5FC5\u987B\u662F\u5B57\u7B26\u4E32\u6570\u7EC4`);return}return[...n]}}function Bi(e){return typeof e==="object"&&e!==null&&!Array.isArray(e)}function j(e,t,r,n=""){let i=t[r];if(i===void 0)return;return e.table(i,n?`${n}.${r}`:r)}function rt(e,t,r){if(e!==void 0&&!/^([01]\d|2[0-3]):[0-5]\d$/.test(e))r.push(`${t} \u5FC5\u987B\u4F7F\u7528 HH:MM\uFF0824 \u5C0F\u65F6\uFF09\u683C\u5F0F`)}function Wr(e,t,r){if(e===void 0)return;try{let n=new URL(e),i=Number(n.port);if(n.protocol!=="tcp:"||!n.hostname||!Number.isInteger(i)||i<1||i>65535)throw Error("invalid")}catch{r.push(`${t} \u5FC5\u987B\u662F tcp://host:port`)}}var Jr=/^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$/;function Hi(e,t){if(t===void 0)return;let r="account.timer_hooks";if(!Array.isArray(t))return e.errors.push(`${r} \u5FC5\u987B\u662F TOML \u8868\u6570\u7EC4`),[];let n=[],i=new Set;for(let[o,s]of t.entries()){let a=`${r}[${o}]`,d=e.table(s,a);e.keys(d,["name","cron","timezone","enabled"],a);let c=e.string(d,"name",a,{required:!0,nonEmpty:!0}),u=e.string(d,"cron",a,{required:!0,nonEmpty:!0}),l=e.string(d,"timezone",a,{required:!0,nonEmpty:!0}),f=e.boolean(d,"enabled",a);if(c!==void 0)if(!Jr.test(c))e.errors.push(`${a}.name \u5FC5\u987B\u5339\u914D ${Jr.source}`);else if(i.has(c))e.errors.push(`${r} \u4E0D\u5141\u8BB8\u91CD\u590D\u540D\u79F0: ${c}`);else i.add(c);let h=u?.trim().replace(/\s+/g," "),m=l?.trim(),v=!1;if(m)try{Bun.cron.parse("0 0 * * *",Date.now(),{tz:m}),v=!0}catch{e.errors.push(`${a}.timezone \u4E0D\u662F\u6709\u6548\u7684 IANA \u65F6\u533A`)}if(h!==void 0&&h.split(" ").length!==5)e.errors.push(`${a}.cron \u5FC5\u987B\u662F 5 \u6BB5 cron \u8868\u8FBE\u5F0F`);else if(h!==void 0&&v)try{if(Bun.cron.parse(h,Date.now(),{tz:m})===null)e.errors.push(`${a}.cron \u5728\u672A\u6765 8 \u5E74\u5185\u6CA1\u6709\u89E6\u53D1\u65F6\u95F4`)}catch{e.errors.push(`${a}.cron \u4E0D\u662F\u6709\u6548\u7684 cron \u8868\u8FBE\u5F0F`)}if(c!==void 0&&h!==void 0&&m!==void 0)n.push({name:c,cron:h,timezone:m,...f===void 0?{}:{enabled:f}})}return n}var Zr=new Set(["CFFEX","SHFE","CZCE","DCE","INE","GFEX"]);function Li(e){let t=e.trim(),r=/^([A-Za-z][A-Za-z0-9]*)\.([A-Za-z]+)$/.exec(t),n=r??/^([A-Za-z][A-Za-z0-9]*)$/.exec(t);if(!n||!/\d/.test(n[1]))throw Error(`\u5408\u7EA6 ${JSON.stringify(e)} \u975E\u6CD5\uFF0C\u5E94\u4F7F\u7528 CODE \u6216 CODE.EXCHANGE`);let i=n[1].toUpperCase(),o=Ni(i),s=r?n[2].toUpperCase():o;if(!s||!Zr.has(s)){if(r)throw Error(`\u5408\u7EA6\u4EA4\u6613\u6240\u975E\u6CD5: ${e}`);throw Error(`\u65E0\u6CD5\u63A8\u65AD\u5408\u7EA6 ${i} \u7684\u4EA4\u6613\u6240\uFF0C\u8BF7\u4F7F\u7528 ${i}.EXCHANGE`)}if(r&&o&&o!==s)throw Error(`\u5408\u7EA6 ${i} \u5E94\u4F7F\u7528\u4EA4\u6613\u6240 ${o}\uFF0C\u800C\u4E0D\u662F ${s}`);return{instrumentID:i,exchangeID:s,vtSymbol:`${i}.${s}`}}function Ni(e){let t=/^[A-Z]+/.exec(e)?.[0];if(!t)return null;let r=new Set;for(let n of qt())if((n.productID.endsWith("_F")?n.productID.slice(0,-2):n.productID)===t)r.add(n.exchangeID);return r.size===1?[...r][0]:null}function jt(e){let t=[],r=new Map;for(let n of e){let i=n.trim(),o=/^([A-Za-z][A-Za-z0-9]*)\.([A-Za-z]+)$/.exec(i);if(!o||!/\d/.test(o[1]))throw Error(`market.record_instruments \u9879 ${JSON.stringify(n)} \u975E\u6CD5\uFF0C\u5E94\u4F7F\u7528 CODE.EXCHANGE`);let s=o[1].toUpperCase(),a=o[2].toUpperCase();if(!Zr.has(a))throw Error(`market.record_instruments \u4EA4\u6613\u6240\u975E\u6CD5: ${n}`);let d=r.get(s);if(d&&d!==a)throw Error(`market.record_instruments \u5408\u7EA6\u4EA4\u6613\u6240\u51B2\u7A81: ${s}.${d} / ${s}.${a}`);if(d)continue;r.set(s,a),t.push({instrumentID:s,exchangeID:a,vtSymbol:`${s}.${a}`})}return t}function Fi(e,t){let r=new Set(e.map((i)=>i.vtSymbol)),n=[...new Set(t.filter((i)=>!r.has(i.vtSymbol)).map((i)=>i.vtSymbol))];if(n.length>0)throw Error(`account.market.bar_hooks \u4F7F\u7528\u4E86\u672A\u5F55\u5236\u8BA2\u9605\u7684\u5408\u7EA6: ${n.join(", ")}`)}function nt(e,t){let r=[],n=new Set;for(let[i,o]of e.entries()){let s;try{s=Li(o.instrument)}catch(d){throw Error(`account.market.bar_hooks[${i}].instrument: ${d instanceof Error?d.message:String(d)}`)}if(!Z(o.timeframe))throw Error(`account.market.bar_hooks[${i}].timeframe \u5FC5\u987B\u662F ${ve}`);let a=`${s.vtSymbol}/${o.timeframe}`;if(n.has(a))throw Error(`account.market.bar_hooks \u4E0D\u5141\u8BB8\u91CD\u590D\u7EC4\u5408: ${a}`);n.add(a),r.push({...s,timeframe:o.timeframe})}return Fi(t,r),r}function Gt(e,t){let r=e?.trim()??"",n=t?.trim()??"";if(!r||!n)return"";let i=`${r}-${n}`;return Ut.test(i)?i:""}function Vi(e,t){let n=e.table(t,"account");e.keys(n,["broker_id","user","ctp","timer_hooks","logging","market","reference_data","trading","schedule"],"account");let i=e.string(n,"broker_id","account",{required:!0,nonEmpty:!0})??"",o=e.string(n,"user","account",{required:!0,nonEmpty:!0})??"";if(!Gt(i,o)&&i&&o)e.errors.push(`${"account"}.broker_id \u4E0E ${"account"}.user \u65E0\u6CD5\u7EC4\u6210\u5408\u6CD5\u8D26\u53F7\u540D`);let a=e.table(n.ctp,"account.ctp");e.keys(a,["market_front","trader_front","front_candidates","password","app_id","auth_code","production_mode"],"account.ctp");let d=e.string(a,"market_front","account.ctp",{required:!0,nonEmpty:!0})??"",c=e.string(a,"trader_front","account.ctp",{required:!0,nonEmpty:!0})??"",u=e.strings(a,"front_candidates","account.ctp"),l=e.string(a,"password","account.ctp"),f=e.string(a,"app_id","account.ctp",{required:!0,nonEmpty:!0})??"",h=e.string(a,"auth_code","account.ctp",{required:!0,nonEmpty:!0})??"",m=e.boolean(a,"production_mode","account.ctp");if(Wr(d||void 0,"account.ctp.market_front",e.errors),Wr(c||void 0,"account.ctp.trader_front",e.errors),u)try{Nt(u.join(","))}catch(S){e.errors.push(`account.ctp.front_candidates: ${S instanceof Error?S.message:String(S)}`)}let v=Hi(e,n.timer_hooks),p=j(e,n,"logging","account");if(p){e.keys(p,["level"],"account.logging");let S=e.string(p,"level","account.logging");if(S!==void 0&&!Kr.includes(S))e.errors.push(`${"account"}.logging.level \u5FC5\u987B\u662F ${Kr.join(" | ")}`)}let k=j(e,n,"market","account");if(k){e.keys(k,["db_path","record_instruments","bar_hooks","tick_time_mode","max_future_tick_ms"],"account.market"),e.string(k,"db_path","account.market");let S=e.strings(k,"record_instruments","account.market"),z=k.bar_hooks,oe=[];if(z!==void 0)if(!Array.isArray(z))e.errors.push(`${"account"}.market.bar_hooks \u5FC5\u987B\u662F TOML \u8868\u6570\u7EC4`);else for(let[A,Zn]of z.entries()){let be=`account.market.bar_hooks[${A}]`,bt=e.table(Zn,be);e.keys(bt,["instrument","timeframe"],be);let yr=e.string(bt,"instrument",be,{required:!0,nonEmpty:!0}),Fe=e.string(bt,"timeframe",be,{required:!0});if(yr!==void 0&&Z(Fe))oe.push({instrument:yr,timeframe:Fe});else if(Fe!==void 0&&!Z(Fe))e.errors.push(`${be}.timeframe \u5FC5\u987B\u662F ${ve}`)}let Ne=e.string(k,"tick_time_mode","account.market");if(Ne!==void 0&&!Yr.includes(Ne))e.errors.push(`${"account"}.market.tick_time_mode \u5FC5\u987B\u662F ${Yr.join(" | ")}`);if(e.integer(k,"max_future_tick_ms","account.market",0,2592000000),S)try{let A=jt(S);nt(oe,A)}catch(A){e.errors.push(A instanceof Error?A.message:String(A))}else if(oe.length>0)try{nt(oe,[])}catch(A){e.errors.push(A instanceof Error?A.message:String(A))}}let q=j(e,n,"reference_data","account");if(q)e.keys(q,["contracts_path","commissions_path"],"account.reference_data"),e.string(q,"contracts_path","account.reference_data"),e.string(q,"commissions_path","account.reference_data");let M=j(e,n,"trading","account");if(M){e.keys(M,["max_order_volume","max_position","max_active_open_orders","daily_limits","duplicate_orders"],"account.trading"),e.integer(M,"max_order_volume","account.trading",1,1e4),e.integer(M,"max_position","account.trading",1,1e5),e.integer(M,"max_active_open_orders","account.trading",1,1000);let S=j(e,M,"daily_limits","account.trading");if(S)e.keys(S,["total_order_limit","total_cancel_limit","total_trade_limit","instrument_order_limit","instrument_cancel_limit","instrument_trade_limit"],"account.trading.daily_limits"),e.integer(S,"total_order_limit","account.trading.daily_limits",1,1e7),e.integer(S,"total_cancel_limit","account.trading.daily_limits",1,1e7),e.integer(S,"total_trade_limit","account.trading.daily_limits",1,1e7),e.integer(S,"instrument_order_limit","account.trading.daily_limits",1,1e7),e.integer(S,"instrument_cancel_limit","account.trading.daily_limits",1,1e7),e.integer(S,"instrument_trade_limit","account.trading.daily_limits",1,1e7);let z=j(e,M,"duplicate_orders","account.trading");if(z)e.keys(z,["duplicate_order_limit"],"account.trading.duplicate_orders"),e.integer(z,"duplicate_order_limit","account.trading.duplicate_orders",2,1000)}let R=j(e,n,"schedule","account");if(R){e.keys(R,["enabled","day_start","day_stop","night_start","night_stop","max_start_attempts","retry_base_ms","tick_ms"],"account.schedule"),e.boolean(R,"enabled","account.schedule");let S=e.string(R,"day_start","account.schedule"),z=e.string(R,"day_stop","account.schedule"),oe=e.string(R,"night_start","account.schedule"),Ne=e.string(R,"night_stop","account.schedule");rt(S,"account.schedule.day_start",e.errors),rt(z,"account.schedule.day_stop",e.errors),rt(oe,"account.schedule.night_start",e.errors),rt(Ne,"account.schedule.night_stop",e.errors),e.integer(R,"max_start_attempts","account.schedule",1,10),e.integer(R,"retry_base_ms","account.schedule",5000,600000),e.integer(R,"tick_ms","account.schedule",5000,120000)}return{identity:{broker_id:i,user:o},ctp:{market_front:d,trader_front:c,...u===void 0?{}:{front_candidates:u},...l===void 0?{}:{password:l},app_id:f,auth_code:h,...m===void 0?{}:{production_mode:m}},...v===void 0?{}:{timer_hooks:v},...p===void 0?{}:{logging:p},...k===void 0?{}:{market:k},...q===void 0?{}:{reference_data:q},...M===void 0?{}:{trading:M},...R===void 0?{}:{schedule:R}}}function qi(e,t=F()){let r=new Qr,n=r.table(e,"config");r.keys(n,["account","storage","server"],"");let i=j(r,n,"storage");if(i)r.keys(i,["data_root"],"storage"),r.string(i,"data_root","storage",{nonEmpty:!0});let o=j(r,n,"server");if(o){r.keys(o,["daemon_port","webui_port"],"server");let l=r.integer(o,"daemon_port","server",1,65535),f=r.integer(o,"webui_port","server",1,65535);if(l!==void 0&&l===f)r.errors.push("server.daemon_port \u4E0E server.webui_port \u4E0D\u80FD\u76F8\u540C")}let s=n.account,a=s===void 0?void 0:Vi(r,s),d=a?.reference_data?.contracts_path?.trim(),c=a?.reference_data?.commissions_path?.trim(),u=a?Gt(a.identity.broker_id,a.identity.user):"";if(a&&u){let l={account:a,...i===void 0?{}:{storage:i}},f=C(le(l,t),"accounts",u),h=d?W(d,t):C(f,"contracts.jsonl"),m=c?W(c,t):C(f,"commissions.jsonl");if(h===m)r.errors.push("account.reference_data.contracts_path \u4E0E commissions_path \u4E0D\u80FD\u6307\u5411\u540C\u4E00\u6587\u4EF6")}if(r.errors.length>0)throw new ee(t,r.errors);return{...a===void 0?{}:{account:a},...i===void 0?{}:{storage:i},...o===void 0?{}:{server:o}}}function zi(e,t=F()){let r;try{r=Bun.TOML.parse(e)}catch(n){throw new ee(t,[`TOML \u8BED\u6CD5\u9519\u8BEF: ${n instanceof Error?n.message:String(n)}`])}return qi(r,t)}function F(){let e=process.env[Mi]?.trim();if(e)return zt(e);if(process.platform==="win32"){let t=process.env.APPDATA??(process.env.USERPROFILE?C(process.env.USERPROFILE,"AppData","Roaming"):C(Ce(),"AppData","Roaming"));return C(t,"vibek","config.toml")}return C(process.env.XDG_CONFIG_HOME??C(Ce(),".config"),"vibek","config.toml")}function Ui(e=F()){if(!xi(e))return{path:e,exists:!1,file:{},errors:[]};try{return{path:e,exists:!0,file:zi(Ci(e,"utf8"),e),errors:[]}}catch(t){if(t instanceof ee)return{path:e,exists:!0,file:null,errors:[...t.diagnostics]};return{path:e,exists:!0,file:null,errors:[t instanceof Error?t.message:String(t)]}}}function ue(e=F()){let t=Ui(e);if(t.errors.length>0||t.file===null)throw new ee(e,t.errors);return t.file}function Xr(e=ue()){let t=Gt(e.account?.identity.broker_id,e.account?.identity.user),r=process.env[Ai]?.trim();if(r){if(r!==t)throw new ee(F(),[`\u5185\u90E8\u8FDB\u7A0B\u8D26\u53F7 ${JSON.stringify(r)} \u4E0E\u5F53\u524D\u914D\u7F6E ${JSON.stringify(t)} \u4E0D\u4E00\u81F4`]);return{name:r,source:"process"}}return t?{name:t,source:"config"}:{name:"",source:"none"}}function W(e,t=F()){let r=e==="~"?Ce():e.startsWith("~/")||e.startsWith("~\\")?C(Ce(),e.slice(2)):e;return $i(r)?zt(r):zt(Pi(t),r)}function le(e=ue(),t=F()){return W(e.storage?.data_root??C(Ce(),".vibek"),t)}function ji(e=ue()){return C(le(e),"accounts")}function en(e,t=ue()){if(!Ut.test(e))throw Error(`\u8D26\u53F7\u540D\u975E\u6CD5: ${e}`);return C(ji(t),e)}import{existsSync as tn,readFileSync as Gi}from"fs";import{isAbsolute as Ki,join as rn,relative as Yi,resolve as Wi}from"path";var Ji=1;function Pe(e=le()){return rn(e,"gateway")}function Qi(e=Pe()){return rn(e,"current.json")}function nn(e=Pe(),t={}){let r=Qi(e);if(!tn(r))return null;try{let n=JSON.parse(Gi(r,"utf8")),i=Zi(n),o=t.platform??process.platform,s=t.arch??process.arch;if(i.platform!==o||i.arch!==s)throw Error(`\u5E73\u53F0\u4E0D\u5339\u914D: ${i.platform}-${i.arch} / ${o}-${s}`);let a=Kt(e,i);if(t.requireExecutable!==!1&&!tn(a))throw Error(`executable \u4E0D\u5B58\u5728: ${a}`);return i}catch(n){if(t.tolerateInvalid)return null;throw Error(`\u53D7\u7BA1 gateway \u72B6\u6001\u65E0\u6548: ${r}: ${n instanceof Error?n.message:String(n)}`)}}function Kt(e,t){let r=Wi(e,t.relativeExecutable),n=Yi(e,r);if(!n||n.startsWith("..")||Ki(n))throw Error("relativeExecutable \u8D8A\u51FA\u53D7\u7BA1 gateway \u76EE\u5F55");return r}function Zi(e){if(!e||typeof e!=="object"||Array.isArray(e))throw Error("\u5FC5\u987B\u662F JSON \u5BF9\u8C61");let t=e,r=t.source;if(!r||typeof r!=="object"||Array.isArray(r))throw Error("source \u5FC5\u987B\u662F JSON \u5BF9\u8C61");let n=r;if(n.kind!=="official"&&n.kind!=="local")throw Error("source.kind \u975E\u6CD5");let i=["releaseKey","gatewayVersion","ctpSdkVersion","platform","arch","relativeExecutable","contentSha256","installedAt"];for(let o of i)if(typeof t[o]!=="string"||!t[o].trim())throw Error(`${o} \u975E\u6CD5`);if(t.formatVersion!==Ji)throw Error("formatVersion \u4E0D\u517C\u5BB9");if(!Number.isInteger(t.protocolVersion)||t.protocolVersion<1)throw Error("protocolVersion \u975E\u6CD5");if(!/^[a-f0-9]{64}$/.test(t.contentSha256))throw Error("contentSha256 \u975E\u6CD5");if(t.archiveSha256!==void 0&&!/^[a-f0-9]{64}$/.test(String(t.archiveSha256)))throw Error("archiveSha256 \u975E\u6CD5");if(typeof n.reference!=="string"||!n.reference)throw Error("source.reference \u975E\u6CD5");return t}import{existsSync as an,realpathSync as Xi}from"fs";import{dirname as eo,join as dn,resolve as on}from"path";var sn=process.platform==="win32"?"ctp_gateway.exe":"ctp_gateway",it=import.meta.dir,cn=it;try{cn=eo(Xi(Bun.main))}catch{}var to="vibek-package.json";function ro(e){return[...new Set(e)].find((t)=>an(dn(t,to)))??""}var ot=ro([cn,it]);var Yt=[on(it,"..","..","ctp-gateway","build","bin","Debug",sn),on(it,"..","..","..","..","ctp-gateway","build","bin","Debug",sn)];function no(e=process.platform){let t=e==="win32"?"ctp_gateway.exe":"ctp_gateway";return e==="linux"?"/opt/vibek-gateway/current/ctp_gateway":e==="darwin"?"/usr/local/lib/vibek-gateway/current/ctp_gateway":dn(process.env.ProgramData??"C:\\ProgramData","Vibek","gateway","current",t)}var un=Yt.find((e)=>an(e))??(ot?no():Yt[Yt.length-1]);var te=ue(),Wt=process.env.VIBEK_PROCESS_ROLE??"",at=Wt==="webui"||Wt==="hooks"?{name:"",source:"none"}:Xr(te),g=at.name?te.account:void 0,mn=g?.ctp.production_mode??!0,hn=g?.ctp.password??"",io=hn.trim().length>0,Jt=jt(g?.market?.record_instruments??[]),oo=nt(g?.market?.bar_hooks??[],Jt),P=le(te),pn=I(P,"hooks"),me=at.name?en(at.name,te):I(P,"accounts",".unresolved"),so=I(me,"vibek_bars.db"),ao=I(me,"contracts.jsonl"),co=I(me,"commissions.jsonl"),gn=ot?nn(Pe(P),{requireExecutable:!0}):null,uo=gn?Kt(Pe(P),gn):un;function st(e){let t=/^([01]\d|2[0-3]):([0-5]\d)$/.exec(e);return{minutes:Number(t[1])*60+Number(t[2]),label:e}}var re={processRole:Wt,account:at.name,packageRoot:ot,broker:g?.identity.broker_id??"",user:g?.identity.user??"",pass:g?io?hn:process.env.VIBEK_PASS||"":"",addr:g?.ctp.market_front??"",traderAddr:g?.ctp.trader_front??"",ctpFronts:g?.ctp.front_candidates?.join(",")??"",ctpProductionMode:mn,authCode:g?.ctp.auth_code??"",appId:g?.ctp.app_id??"",logLevel:g?.logging?.level??(mn?"info":"debug"),daemonPort:te.server?.daemon_port??3111,daemonHttpUrl:`http://127.0.0.1:${te.server?.daemon_port??3111}`,webui:{port:te.server?.webui_port??3211},gatewayPath:uo,timerHooks:(g?.timer_hooks??[]).map((e)=>({name:e.name,cron:e.cron,timezone:e.timezone,enabled:e.enabled??!0})),market:{instruments:Jt.map((e)=>e.instrumentID),declarations:Jt,barHooks:oo,tickTimeMode:g?.market?.tick_time_mode??"realtime",maxFutureTickMs:g?.market?.max_future_tick_ms??5000,testFlush:process.env.VIBEK_TEST_FLUSH!==void 0},trading:{maxOrderVolume:g?.trading?.max_order_volume??10,maxPosition:g?.trading?.max_position??20,maxActiveOpenOrders:g?.trading?.max_active_open_orders??5,dailyLimits:{totalOrderLimit:g?.trading?.daily_limits?.total_order_limit??20000,totalCancelLimit:g?.trading?.daily_limits?.total_cancel_limit??1e4,totalTradeLimit:g?.trading?.daily_limits?.total_trade_limit??1e4,instrumentOrderLimit:g?.trading?.daily_limits?.instrument_order_limit??2000,instrumentCancelLimit:g?.trading?.daily_limits?.instrument_cancel_limit??1000,instrumentTradeLimit:g?.trading?.daily_limits?.instrument_trade_limit??1000},duplicateOrders:{duplicateOrderLimit:g?.trading?.duplicate_orders?.duplicate_order_limit??10}},schedule:{enabled:g?.schedule?.enabled??!0,dayStart:st(g?.schedule?.day_start??"08:45"),dayStop:st(g?.schedule?.day_stop??"15:15"),nightStart:st(g?.schedule?.night_start??"20:45"),nightStop:st(g?.schedule?.night_stop??"02:35"),maxStartAttempts:g?.schedule?.max_start_attempts??4,retryBaseMs:g?.schedule?.retry_base_ms??30000,tickMs:g?.schedule?.tick_ms??30000}},pe={config:F(),root:P,accounts:I(P,"accounts"),ai:I(P,"ai"),aiWorkspace:ln(I(P,"ai-workspace"))||!ln(I(P,"tui-workspace"))?I(P,"ai-workspace"):I(P,"tui-workspace"),hooks:pn,hooksSocket:I(P,"run","hooks.sock"),hookHostsDb:I(pn,"hosts.sqlite"),data:me,logs:I(me,"logs"),gatewayWorkdir:I(me,"gateway"),db:g?.market?.db_path?W(g.market.db_path):so,contracts:g?.reference_data?.contracts_path?.trim()?W(g.reference_data.contracts_path):ao,commissions:g?.reference_data?.commissions_path?.trim()?W(g.reference_data.commissions_path):co};var dt=30000;var sd=Number.MAX_VALUE/2;import{randomUUID as Fo}from"crypto";var ct=/^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$/,lo=/^[A-Z][A-Z0-9]*\.[A-Z]+$/,ut=/^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$/;function O(e){return typeof e==="object"&&e!==null&&!Array.isArray(e)}function mo(e,t){let r=new Set(t);return Object.keys(e).every((n)=>r.has(n))}function y(e,t){return mo(e,t)&&t.every((r)=>Object.hasOwn(e,r))}function V(e,t=4096){return typeof e==="string"&&e.length>0&&e.length<=t}function ge(e){return typeof e==="string"&&lo.test(e)&&/\d/.test(e.split(".")[0]??"")}function lt(e){if(typeof e!=="string"||!/^\d{8}$/.test(e))return!1;let t=Number(e.slice(0,4)),r=Number(e.slice(4,6)),n=Number(e.slice(6,8)),i=new Date(Date.UTC(t,r-1,n));return i.getUTCFullYear()===t&&i.getUTCMonth()===r-1&&i.getUTCDate()===n}function Qt(e,t,r=new Set){if(e===null||typeof e==="string"||typeof e==="boolean")return e;if(typeof e==="number"){if(!Number.isFinite(e))throw Error(`${t} contains a non-finite number`);return e}if(typeof e!=="object")throw Error(`${t} is not JSON`);if(r.has(e))throw Error(`${t} contains a cycle`);r.add(e);try{if(Array.isArray(e)){let i=[];for(let o=0;o<e.length;o++){if(!Object.hasOwn(e,o))throw Error(`${t}[${o}] is not JSON`);i.push(Qt(e[o],`${t}[${o}]`,r))}return i}let n=Object.getPrototypeOf(e);if(n!==Object.prototype&&n!==null)throw Error(`${t} is not a plain object`);return Object.fromEntries(Object.entries(e).map(([i,o])=>[i,Qt(o,`${t}.${i}`,r)]))}finally{r.delete(e)}}function fn(e,t){if(!O(e))throw Error(`${t} is not JSON`);let r=Qt(e,t);if(!O(r))throw Error(`${t} is not JSON`);return r}function yn(e,t){if(!O(t))throw Error(`invalid payload for ${e}`);if(e==="daemon.ready"){if(y(t,[]))return{}}else if(e==="daemon.stopping"){if(y(t,["signal"])&&(t.signal==="API"||t.signal==="SIGINT"||t.signal==="SIGTERM"))return{signal:t.signal}}else if(e==="daemon.service.faulted"){if(y(t,["service","reason"])&&(t.service==="market"||t.service==="trading")&&typeof t.reason==="string"&&t.reason.length>0&&t.reason.length<=4096)return{service:t.service,reason:t.reason}}else if(y(t,["service"])&&(t.service==="market"||t.service==="trading"))return{service:t.service};throw Error(`invalid payload for ${e}`)}var bn=["1min","3min","5min","10min","15min","30min","1h","2h","4h","1d"];function Zt(e){return typeof e==="string"&&bn.includes(e)}function wn(e,t){let r=["vtSymbol","timeframe","barTime","open","high","low","close","volume","tradingDay"];if(typeof t!=="object"||t===null||Array.isArray(t))throw Error(`invalid payload for ${e}`);let n=t,i=y(n,r)||y(n,[...r,"boundaryReason"]),o=[n.open,n.high,n.low,n.close,n.volume];if(!i||!ge(n.vtSymbol)||!Zt(n.timeframe)||!Number.isSafeInteger(n.barTime)||Number(n.barTime)<0||!o.every((s)=>typeof s==="number"&&Number.isFinite(s))||Number(n.volume)<0||n.tradingDay!==null&&!lt(n.tradingDay)||n.boundaryReason!==void 0&&n.boundaryReason!=="break"&&n.boundaryReason!=="sessionEnd"&&n.boundaryReason!=="disconnect")throw Error(`invalid payload for ${e}`);return{vtSymbol:n.vtSymbol,timeframe:n.timeframe,barTime:n.barTime,open:n.open,high:n.high,low:n.low,close:n.close,volume:n.volume,tradingDay:n.tradingDay,...n.boundaryReason===void 0?{}:{boundaryReason:n.boundaryReason}}}var Sn=["strategy","manual"],vn=["max_order_volume","max_position","max_active_open_orders","trading_day_unresolved","trading_day_mismatch","daily_total_order_limit","daily_total_cancel_limit","daily_total_trade_limit","daily_instrument_order_limit","daily_instrument_cancel_limit","daily_instrument_trade_limit","duplicate_order_limit"];function kn(e,t){if(e!=="risk.order_rejected"||!O(t)||!y(t,["source","riskCode","mode","vtSymbol","tradingDay","direction","offset","price","volume","reason"].concat(Object.hasOwn(t,"strategyId")?["strategyId"]:[]))||!Sn.includes(t.source)||!vn.includes(t.riskCode)||t.mode!=="paper"&&t.mode!=="live"||!ge(t.vtSymbol)||t.tradingDay!==null&&!lt(t.tradingDay)||t.direction!=="long"&&t.direction!=="short"||!["open","close","closeToday","closeYesterday"].includes(String(t.offset))||typeof t.price!=="number"||!Number.isFinite(t.price)||t.price<=0||!Number.isSafeInteger(t.volume)||Number(t.volume)<=0||!V(t.reason)||Object.hasOwn(t,"strategyId")&&(typeof t.strategyId!=="string"||!ct.test(t.strategyId)))throw Error(`invalid payload for ${e}`);return{source:t.source,riskCode:t.riskCode,mode:t.mode,vtSymbol:t.vtSymbol,tradingDay:t.tradingDay,direction:t.direction,offset:t.offset,price:t.price,volume:t.volume,reason:t.reason,...typeof t.strategyId==="string"?{strategyId:t.strategyId}:{}}}var Tn=["window","windowId"];function po(e){return(e.window==="day"||e.window==="night")&&V(e.windowId,128)&&e.windowId.endsWith(`/${e.window}`)}function En(e,t){if(!O(t)||!po(t))throw Error(`invalid payload for ${e}`);let r={window:t.window,windowId:t.windowId};if(e==="schedule.window.opened"||e==="schedule.window.closed"){if(y(t,Tn))return r}else if(y(t,[...Tn,"attempts","reason"])&&Number.isSafeInteger(t.attempts)&&Number(t.attempts)>0&&V(t.reason))return{...r,attempts:t.attempts,reason:t.reason};throw Error(`invalid payload for ${e}`)}var he=["strategyId","mode","vtSymbol"];function go(e){return typeof e.strategyId==="string"&&ct.test(e.strategyId)&&(e.mode==="paper"||e.mode==="live")&&ge(e.vtSymbol)}function ho(e){return{strategyId:e.strategyId,mode:e.mode,vtSymbol:e.vtSymbol}}function In(e,t){if(!O(t)||!go(t))throw Error(`invalid payload for ${e}`);let r=ho(t);switch(e){case"strategy.loaded":if(!y(t,[...he,"replaced"])||typeof t.replaced!=="boolean")break;return{...r,replaced:t.replaced};case"strategy.unloaded":case"strategy.enabled":case"strategy.disabled":case"strategy.started":case"strategy.stopped":if(!y(t,he))break;return r;case"strategy.start_failed":if(!y(t,[...he,"reason"])||!V(t.reason))break;return{...r,reason:t.reason};case"strategy.orders_retained":if(!y(t,[...he,"activeOrders","reason"])||!Number.isSafeInteger(t.activeOrders)||Number(t.activeOrders)<=0||!V(t.reason))break;return{...r,activeOrders:t.activeOrders,reason:t.reason};case"strategy.faulted":if(!y(t,[...he,"callback","reason"])||!V(t.callback,128)||!V(t.reason))break;return{...r,callback:t.callback,reason:t.reason};case"strategy.event":{if(!y(t,[...he,"name","data"])||typeof t.name!=="string"||!ut.test(t.name))break;let n=fn(t.data,"strategy.event.data");return{...r,name:t.name,data:n}}}throw Error(`invalid payload for ${e}`)}function Dn(e,t){if(!O(t)||!y(t,["name"])||typeof t.name!=="string"||!ut.test(t.name))throw Error(`invalid payload for ${e}`);return{name:t.name}}var Xt=65536;function er(e,t){if(e.startsWith("risk."))return kn(e,t);if(e.startsWith("strategy."))return In(e,t);if(e.startsWith("timer."))return Dn(e,t);if(e.startsWith("schedule."))return En(e,t);if(e.startsWith("market."))return wn(e,t);return yn(e,t)}function fe(e){let t=new TextEncoder().encode(JSON.stringify(e));if(t.byteLength>Xt)throw Error(`hook frame exceeds ${Xt} bytes`);let r=new Uint8Array(4+t.byteLength);return new DataView(r.buffer).setUint32(0,t.byteLength,!1),r.set(t,4),r}import{Database as So}from"bun:sqlite";function Rn(e){e.run("PRAGMA journal_mode=WAL"),e.run(`
5
5
  CREATE TABLE IF NOT EXISTS bars (
6
6
  id INTEGER PRIMARY KEY AUTOINCREMENT,
7
7
  code TEXT NOT NULL,
@@ -22,7 +22,22 @@ ${t.map((r)=>` - ${r}`).join(`
22
22
  `),e.run(`
23
23
  CREATE INDEX IF NOT EXISTS idx_bars_code_tf_time
24
24
  ON bars(code, timeframe, bar_time)
25
- `)}function ne(e){return{code:e.code,timeframe:e.timeframe,barTime:e.bar_time,open:e.open,high:e.high,low:e.low,close:e.close,volume:e.volume,...e.trading_day?{tradingDay:e.trading_day}:{},...e.boundary_reason?{boundaryReason:e.boundary_reason}:{}}}var xn=pe.db;function nr(e=!1,t){return new _n(t??xn,e)}class _n{db;barCallbacks=[];constructor(e,t=!1){if(this.db=new So(e,{readonly:t,create:!t}),!t)Rn(this.db)}async getHistoricalBars(e,t,r){return this.db.query(`SELECT code, timeframe, bar_time, open, high, low, close, volume, trading_day, boundary_reason, created_at
25
+ `),e.run(`CREATE TABLE IF NOT EXISTS market_ticks (
26
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
27
+ instrument_id TEXT NOT NULL,
28
+ stream_id TEXT NOT NULL,
29
+ price_tick REAL NOT NULL,
30
+ trading_day TEXT NOT NULL,
31
+ event_time_ms INTEGER NOT NULL,
32
+ aggregation_time_ms INTEGER,
33
+ received_at_ms INTEGER NOT NULL,
34
+ last_price REAL NOT NULL,
35
+ volume INTEGER NOT NULL CHECK(volume >= 0),
36
+ bid_price1 REAL,
37
+ ask_price1 REAL,
38
+ bid_volume1 INTEGER,
39
+ ask_volume1 INTEGER
40
+ )`),e.run("CREATE INDEX IF NOT EXISTS idx_market_ticks_instrument_id ON market_ticks(instrument_id, id)")}function ne(e){return{code:e.code,timeframe:e.timeframe,barTime:e.bar_time,open:e.open,high:e.high,low:e.low,close:e.close,volume:e.volume,...e.trading_day?{tradingDay:e.trading_day}:{},...e.boundary_reason?{boundaryReason:e.boundary_reason}:{}}}function vo(e){let{aggregationTimeMs:t,bidPrice1:r,askPrice1:n,bidVolume1:i,askVolume1:o,...s}=e;return{...s,...t===null?{}:{aggregationTimeMs:t},...r===null?{}:{bidPrice1:r},...n===null?{}:{askPrice1:n},...i===null?{}:{bidVolume1:i},...o===null?{}:{askVolume1:o}}}var _n=pe.db;function nr(e=!1,t){return new xn(t??_n,e)}class xn{db;barCallbacks=[];constructor(e,t=!1){if(this.db=new So(e,{readonly:t,create:!t}),!t)Rn(this.db)}async getHistoricalBars(e,t,r){return this.db.query(`SELECT code, timeframe, bar_time, open, high, low, close, volume, trading_day, boundary_reason, created_at
26
41
  FROM bars WHERE code = ? AND timeframe = ? ORDER BY bar_time ASC LIMIT ?`).all(e,t,r).map(ne)}async getLatestBars(e,t,r){return this.db.query(`SELECT code, timeframe, bar_time, open, high, low, close, volume, trading_day, boundary_reason, created_at
27
42
  FROM (SELECT code, timeframe, bar_time, open, high, low, close, volume, trading_day, boundary_reason, created_at
28
43
  FROM bars WHERE code = ? AND timeframe = ?
@@ -39,14 +54,21 @@ ${t.map((r)=>` - ${r}`).join(`
39
54
  FROM bars WHERE code = ? AND timeframe = ? AND bar_time <= ?`).get(e,t,r))??null;if(!n||n.barCount===0||n.firstBarTime===null||n.lastBarTime===null)return null;return{code:e,timeframe:t,...n,firstBarTime:n.firstBarTime,lastBarTime:n.lastBarTime}}getBarAt(e,t,r){let n=this.db.query(`SELECT code, timeframe, bar_time, open, high, low, close, volume, trading_day, boundary_reason, created_at
40
55
  FROM bars WHERE code = ? AND timeframe = ? AND bar_time = ?`).get(e,t,r);return n?ne(n):null}*iterateBars(e,t){let r=this.db.prepare(`SELECT code, timeframe, bar_time, open, high, low, close, volume, trading_day, boundary_reason, created_at
41
56
  FROM bars WHERE code = ? AND timeframe = ? ORDER BY bar_time ASC`);try{for(let n of r.iterate(e,t))yield ne(n)}finally{r.finalize()}}*iterateBarsRange(e,t,r,n){let i=this.db.prepare(`SELECT code, timeframe, bar_time, open, high, low, close, volume, trading_day, boundary_reason, created_at
42
- FROM bars WHERE code = ? AND timeframe = ? AND bar_time > ? AND bar_time <= ? ORDER BY bar_time ASC`);try{for(let o of i.iterate(e,t,r,n))yield ne(o)}finally{i.finalize()}}getAllCodes(){return this.db.query("SELECT DISTINCT code FROM bars ORDER BY code").all().map((t)=>t.code)}insertBars(e){let t=Math.floor(Date.now()/1000),r=this.db.prepare(`INSERT OR IGNORE INTO bars (code, timeframe, bar_time, open, high, low, close, volume, trading_day, boundary_reason, created_at)
43
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`),n=0;try{for(let i of e)if(r.run(i.code,i.timeframe,i.barTime,i.open,i.high,i.low,i.close,i.volume,i.tradingDay??null,i.boundaryReason??null,t).changes>0)n++;return n}finally{r.finalize()}}onBar(e){this.barCallbacks.push(e)}emitBar(e){for(let t of this.barCallbacks)t(e)}destroy(){this.barCallbacks=[],this.db.close()}}import{existsSync as vo,mkdirSync as ko,readFileSync as To,renameSync as Eo,unlinkSync as Cn,writeFileSync as Io}from"fs";import{randomUUID as Do}from"crypto";import{join as ir}from"path";var Oo=new Set(["strategyId","vtSymbol","mode","bundleHash","savedAt","pos","variables","inventory","tradingDay"]);class $n extends Error{details;code="strategy_state_incompatible";constructor(e){super(`\u7B56\u7565 ${e.oldState.strategyId}@${e.oldState.mode} \u72B6\u6001 schema \u4E0D\u517C\u5BB9\uFF0C\u672A\u52A0\u8F7D\u65B0\u7B56\u7565\u3002
57
+ FROM bars WHERE code = ? AND timeframe = ? AND bar_time > ? AND bar_time <= ? ORDER BY bar_time ASC`);try{for(let o of i.iterate(e,t,r,n))yield ne(o)}finally{i.finalize()}}getAllCodes(){return this.db.query("SELECT DISTINCT code FROM bars ORDER BY code").all().map((t)=>t.code)}insertTick(e){if(!e.streamID)throw Error("\u5F55\u5236 Tick \u7F3A\u5C11\u8FDE\u7EED\u6BB5\u6807\u8BC6");let t=this.db.query(`INSERT INTO market_ticks (
58
+ instrument_id, stream_id, price_tick, trading_day, event_time_ms, aggregation_time_ms,
59
+ received_at_ms, last_price, volume, bid_price1, ask_price1, bid_volume1, ask_volume1
60
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(e.instrumentID,e.streamID,e.priceTick,e.tradingDay,e.eventTimeMs,e.aggregationTimeMs??null,e.receivedAtMs,e.lastPrice,e.volume,e.bidPrice1??null,e.askPrice1??null,e.bidVolume1??null,e.askVolume1??null);return{...e,sequence:Number(t.lastInsertRowid)}}getLatestTicks(e,t,r){if(!Number.isSafeInteger(t)||t<1||t>40000||r!==void 0&&(!Number.isSafeInteger(r)||r<=0))throw Error("Tick \u67E5\u8BE2\u8303\u56F4\u65E0\u6548");let n=this.db.query(`SELECT id AS sequence, stream_id AS streamID, instrument_id AS instrumentID,
61
+ price_tick AS priceTick, trading_day AS tradingDay, event_time_ms AS eventTimeMs,
62
+ aggregation_time_ms AS aggregationTimeMs, received_at_ms AS receivedAtMs, last_price AS lastPrice,
63
+ volume, bid_price1 AS bidPrice1, ask_price1 AS askPrice1, bid_volume1 AS bidVolume1, ask_volume1 AS askVolume1
64
+ FROM market_ticks WHERE instrument_id = ? ${r===void 0?"":"AND id < ?"} ORDER BY id DESC LIMIT ?`).all(e.toUpperCase(),...r===void 0?[]:[r],t+1),i=n.length>t,o=n.slice(0,t).reverse().map(vo);return{instrumentID:e.toUpperCase(),ticks:o,hasMore:i}}insertBars(e){let t=Math.floor(Date.now()/1000),r=this.db.prepare(`INSERT OR IGNORE INTO bars (code, timeframe, bar_time, open, high, low, close, volume, trading_day, boundary_reason, created_at)
65
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`),n=0;try{for(let i of e)if(r.run(i.code,i.timeframe,i.barTime,i.open,i.high,i.low,i.close,i.volume,i.tradingDay??null,i.boundaryReason??null,t).changes>0)n++;return n}finally{r.finalize()}}onBar(e){this.barCallbacks.push(e)}emitBar(e){for(let t of this.barCallbacks)t(e)}destroy(){this.barCallbacks=[],this.db.close()}}import{existsSync as ko,mkdirSync as To,readFileSync as Eo,renameSync as Io,unlinkSync as Cn,writeFileSync as Do}from"fs";import{randomUUID as Oo}from"crypto";import{join as ir}from"path";var Ro=new Set(["strategyId","vtSymbol","mode","bundleHash","savedAt","pos","variables","inventory","tradingDay"]);class $n extends Error{details;code="strategy_state_incompatible";constructor(e){super(`\u7B56\u7565 ${e.oldState.strategyId}@${e.oldState.mode} \u72B6\u6001 schema \u4E0D\u517C\u5BB9\uFF0C\u672A\u52A0\u8F7D\u65B0\u7B56\u7565\u3002
44
66
  `+`\u72B6\u6001\u6587\u4EF6: ${e.statePath}
45
67
  `+`\u65E7 schema: ${JSON.stringify(e.oldSchema)}
46
68
  `+`\u65B0\u7B56\u7565\u671F\u671B schema: ${JSON.stringify(e.newSchema)}
47
- `+`\u82E5\u8981\u653E\u5F03\u65E7\u72B6\u6001\uFF0C\u8BF7\u6267\u884C vibek strategy unload ${e.oldState.strategyId}@${e.oldState.mode} \u540E\u91CD\u65B0 load\uFF1B`+"unload \u4F1A\u6C38\u4E45\u5220\u9664\u8BE5\u6A21\u5F0F\u7684\u72B6\u6001\u3001\u6301\u4ED3\u548C\u53D8\u91CF\u3002\u82E5\u5F53\u524D\u6CA1\u6709\u5DF2\u52A0\u8F7D\u5B9E\u4F8B\uFF0C\u8BF7\u6309\u4E0A\u8FF0\u8DEF\u5F84\u624B\u52A8\u5220\u9664\u65E7 state \u6587\u4EF6\u3002");this.details=e;this.name="StrategyStateCompatibilityError"}}function or(e){return e!==null&&typeof e==="object"&&!Array.isArray(e)}function mt(e,t,r){if(!Number.isInteger(e)||e<0)throw Error(`${r}: ${t} \u975E\u6CD5`);return e}function Pn(e,t){if(!or(e))throw Error(`${t}: \u7B56\u7565\u72B6\u6001\u5FC5\u987B\u662F\u5BF9\u8C61`);if(Object.keys(e).some((i)=>!Oo.has(i)))throw Error(`${t}: \u7B56\u7565\u72B6\u6001\u5305\u542B\u672A\u77E5\u5B57\u6BB5`);if(typeof e.strategyId!=="string"||typeof e.vtSymbol!=="string"||e.mode!=="paper"&&e.mode!=="live")throw Error(`${t}: \u7B56\u7565\u72B6\u6001\u8EAB\u4EFD\u975E\u6CD5`);if(typeof e.bundleHash!=="string"||!/^[a-f0-9]{64}$/.test(e.bundleHash)||typeof e.savedAt!=="string"||!or(e.variables)||typeof e.tradingDay!=="string"||!or(e.inventory))throw Error(`${t}: \u7B56\u7565\u72B6\u6001\u5185\u5BB9\u975E\u6CD5`);let r={longToday:mt(e.inventory.longToday,"longToday",t),longYesterday:mt(e.inventory.longYesterday,"longYesterday",t),shortToday:mt(e.inventory.shortToday,"shortToday",t),shortYesterday:mt(e.inventory.shortYesterday,"shortYesterday",t)};if(!Number.isInteger(e.pos))throw Error(`${t}: pos \u975E\u6CD5`);if(r.longToday+r.longYesterday-r.shortToday-r.shortYesterday!==e.pos)throw Error(`${t}: pos \u4E0E inventory \u4E0D\u4E00\u81F4`);return{strategyId:e.strategyId,vtSymbol:e.vtSymbol,mode:e.mode,bundleHash:e.bundleHash,savedAt:e.savedAt,pos:e.pos,variables:e.variables,inventory:r,tradingDay:e.tradingDay}}class $e{root;constructor(e=pe.data){this.root=ir(e,"strategy-state")}read(e,t){let r=this.path(e,t);if(!vo(r))return null;return Pn(JSON.parse(To(r,"utf8")),r)}assertCompatible(e,t,r,n){let i=this.read(e,t);if(!i)return;if(i.strategyId!==e||i.mode!==t)throw Error(`${this.path(e,t)}: \u7B56\u7565 ${e} \u72B6\u6001\u8EAB\u4EFD\u4E0D\u5339\u914D`);if(i.vtSymbol!==r)throw Error(`${this.path(e,t)}: \u7B56\u7565 ${e} \u7684\u72B6\u6001\u5C5E\u4E8E ${i.vtSymbol}\uFF0C\u4E0D\u80FD\u6062\u590D\u5230 ${r}`);let o=Object.keys(i.variables).sort(),s=[...n].sort(),a=new Set(o),d=new Set(s),c=s.filter((l)=>!a.has(l)),u=o.filter((l)=>!d.has(l));if(c.length===0&&u.length===0)return;throw new $n({statePath:this.path(e,t),oldState:i,oldSchema:{variables:o},newSchema:{variables:s},addedVariables:c,removedVariables:u})}write(e){let t=this.path(e.strategyId,e.mode);ko(ir(this.root,e.strategyId),{recursive:!0});let r={savedAt:new Date().toISOString(),...e};Pn(r,t);let n=`${JSON.stringify(r,null,2)}
48
- `;if(Buffer.byteLength(n)>262144)throw Error(`\u7B56\u7565 ${e.strategyId} variables \u8D85\u8FC7 256KB`);let i=`${t}.${process.pid}-${Do()}.tmp`;try{Io(i,n,{encoding:"utf8",mode:384,flag:"wx"}),Eo(i,t)}finally{try{Cn(i)}catch{}}}remove(e,t){let r=this.path(e,t);try{return Cn(r),!0}catch(n){if(n.code==="ENOENT")return!1;throw n}}path(e,t){if(!we.test(e))throw Error(`\u7B56\u7565 ID \u975E\u6CD5: ${e}`);if(t!=="paper"&&t!=="live")throw Error(`\u7B56\u7565 mode \u975E\u6CD5: ${t}`);return ir(this.root,e,`${t}.json`)}}import{randomUUID as Ro}from"crypto";import{existsSync as xo,mkdirSync as _o,readFileSync as Co,renameSync as Po,unlinkSync as $o,writeFileSync as Mo}from"fs";import{dirname as Ao,join as Bo}from"path";var pt=(e,t)=>{let r=setTimeout(e,t);return()=>clearTimeout(r)};var Mn=4194304,gt=/^\d{8}$/;function ar(){return{orders:0,cancels:0,trades:0}}function Me(e=""){return{tradingDay:e,total:ar(),instruments:new Map,duplicateAttempts:new Map,duplicateRejected:0,orderIds:new Set,cancelledOrderIds:new Set,tradeIds:new Set}}function Ae(e){return e!==null&&typeof e==="object"&&!Array.isArray(e)}function Be(e,t){if(!Number.isSafeInteger(e)||e<0)throw Error(`${t} \u5FC5\u987B\u662F\u975E\u8D1F\u6574\u6570`);return e}function An(e,t){if(!Ae(e))throw Error(`${t} \u5FC5\u987B\u662F JSON \u5BF9\u8C61`);return{orders:Be(e.orders,`${t}.orders`),cancels:Be(e.cancels,`${t}.cancels`),trades:Be(e.trades,`${t}.trades`)}}function Bn(e,t){if(!Ae(e))throw Error(`${t} \u5FC5\u987B\u662F JSON \u5BF9\u8C61`);let r=typeof e.tradingDay==="string"?e.tradingDay:"";if(r&&!gt.test(r))throw Error(`${t}.tradingDay \u975E\u6CD5`);if(!Ae(e.instruments))throw Error(`${t}.instruments \u5FC5\u987B\u662F JSON \u5BF9\u8C61`);let n={};for(let[o,s]of Object.entries(e.instruments)){if(!o||o.length>128)throw Error(`${t}.instruments key \u975E\u6CD5`);n[o]=An(s,`${t}.instruments.${o}`)}if(!Ae(e.duplicateAttempts))throw Error(`${t}.duplicateAttempts \u5FC5\u987B\u662F JSON \u5BF9\u8C61`);let i={};for(let[o,s]of Object.entries(e.duplicateAttempts))i[o]=Be(s,`${t}.duplicateAttempts`);return{tradingDay:r,total:An(e.total,`${t}.total`),instruments:n,duplicateAttempts:i,duplicateRejected:Be(e.duplicateRejected,`${t}.duplicateRejected`)}}function Hn(e,t){if(!Ae(e)||Object.keys(e).some((r)=>!["savedAt","paper","live"].includes(r))||typeof e.savedAt!=="string")throw Error(`${t}: \u98CE\u63A7\u72B6\u6001\u7ED3\u6784\u975E\u6CD5`);return{savedAt:e.savedAt,paper:Bn(e.paper,`${t}.paper`),live:Bn(e.live,`${t}.live`)}}function Ln(e){return{tradingDay:e.tradingDay,total:{...e.total},instruments:new Map(Object.entries(e.instruments).map(([t,r])=>[t,{...r}])),duplicateAttempts:new Map(Object.entries(e.duplicateAttempts)),duplicateRejected:e.duplicateRejected,orderIds:new Set,cancelledOrderIds:new Set,tradeIds:new Set}}function Nn(e){return{tradingDay:e.tradingDay,total:{...e.total},instruments:Object.fromEntries([...e.instruments.entries()].sort(([t],[r])=>t.localeCompare(r)).map(([t,r])=>[t,{...r}])),duplicateAttempts:Object.fromEntries([...e.duplicateAttempts.entries()].sort(([t],[r])=>t.localeCompare(r))),duplicateRejected:e.duplicateRejected}}function Ho(){return{dailyLimits:{...re.trading.dailyLimits},duplicateOrderLimit:re.trading.duplicateOrders.duplicateOrderLimit}}function Fn(e){return JSON.stringify([e.vtSymbol.toUpperCase(),e.direction,e.offset,e.price,e.volume])}function sr(e,t){e.orders=Math.max(e.orders,t.orders),e.cancels=Math.max(e.cancels,t.cancels),e.trades=Math.max(e.trades,t.trades)}function Lo(e){let t=ar();for(let r of e)t.orders+=r.orders,t.cancels+=r.cancels,t.trades+=r.trades;return t}class dr{path;constructor(e=pe.data){this.path=Bo(e,"risk-state.json")}read(){if(!xo(this.path))return null;let e=Co(this.path,"utf8");if(Buffer.byteLength(e)>Mn)throw Error(`${this.path}: \u98CE\u63A7\u72B6\u6001\u8D85\u8FC7 4MB`);try{return Hn(JSON.parse(e),this.path)}catch(t){throw Error(`${this.path}: \u98CE\u63A7\u72B6\u6001\u65E0\u6548: ${t instanceof Error?t.message:String(t)}`)}}write(e){let t={savedAt:new Date().toISOString(),...e};Hn(t,this.path);let r=`${JSON.stringify(t,null,2)}
49
- `;if(Buffer.byteLength(r)>Mn)throw Error(`${this.path}: \u98CE\u63A7\u72B6\u6001\u8D85\u8FC7 4MB`);_o(Ao(this.path),{recursive:!0});let n=`${this.path}.${process.pid}-${Ro()}.tmp`;try{Mo(n,r,{encoding:"utf8",mode:384,flag:"wx"}),Po(n,this.path)}finally{try{$o(n)}catch{}}}}class He{settings;paper=Me();live=Me();stateStore;persistDelayMs;schedule;persistTimer=null;dirty=!1;constructor(e={}){this.settings=e.settings??Ho(),this.stateStore=e.stateStore??null,this.persistDelayMs=e.persistDelayMs??250,this.schedule=e.schedule??pt;let t=this.stateStore?.read();if(t)this.paper=Ln(t.paper),this.live=Ln(t.live)}setTradingDay(e,t){if(!gt.test(t))return;let r=this.mode(e);if(r.tradingDay===t)return;if(r.tradingDay&&t<r.tradingDay)return;this.replaceMode(e,Me(t)),this.markDirty()}checkOpen(e){return this.checkOpenDetailed(e)?.message??null}checkOpenDetailed(e,t={}){if(e.offset!=="open")return null;let r=t.recordAttempt!==!1,n;if(r)this.setTradingDay(e.mode,e.tradingDay),n=this.mode(e.mode);else{let a=this.mode(e.mode);n=gt.test(e.tradingDay)&&(!a.tradingDay||e.tradingDay>a.tradingDay)?Me(e.tradingDay):a}if(!n.tradingDay)return{code:"trading_day_unresolved",message:"\u98CE\u63A7 TradingDay \u5C1A\u672A\u786E\u5B9A"};if(n.tradingDay!==e.tradingDay)return{code:"trading_day_mismatch",message:`\u98CE\u63A7 TradingDay \u4E0D\u4E00\u81F4 ${n.tradingDay}/${e.tradingDay||"(\u7A7A)"}`};let i=this.dailyFailure(n,e.vtSymbol.toUpperCase());if(i)return i;let o=Fn(e),s=(n.duplicateAttempts.get(o)??0)+1;if(s>=this.settings.duplicateOrderLimit){if(r)n.duplicateAttempts.set(o,s),n.duplicateRejected++,this.markDirty();return{code:"duplicate_order_limit",message:`\u76F8\u540C\u5F00\u4ED3\u8BF7\u6C42\u5F53\u65E5\u7B2C ${s} \u6B21\uFF0C\u8FBE\u5230\u91CD\u590D\u62A5\u5355\u9608\u503C ${this.settings.duplicateOrderLimit}`}}if(r)n.duplicateAttempts.set(o,s),this.markDirty();return null}recordOrder(e,t,r=""){if(r)this.setTradingDay(e,r);let n=this.mode(e);if(!n.tradingDay||r&&n.tradingDay!==r)return;let i=t.vtSymbol.toUpperCase(),o=!1;if(!n.orderIds.has(t.vtOrderId))n.orderIds.add(t.vtOrderId),this.increment(n,i,"orders"),o=!0;if(t.status==="cancelled"&&!n.cancelledOrderIds.has(t.vtOrderId))n.cancelledOrderIds.add(t.vtOrderId),this.increment(n,i,"cancels"),o=!0;if(o)this.markDirty()}recordTrade(e,t){this.setTradingDay(e,t.tradingDay);let r=this.mode(e);if(!r.tradingDay||r.tradingDay!==t.tradingDay||r.tradeIds.has(t.vtTradeId))return;r.tradeIds.add(t.vtTradeId),this.increment(r,t.vtSymbol.toUpperCase(),"trades"),this.markDirty()}reconcileLive(e){if(!gt.test(e.tradingDay))throw Error(`Live \u98CE\u63A7 TradingDay \u975E\u6CD5: ${e.tradingDay}`);if(this.setTradingDay("live",e.tradingDay),this.live.tradingDay!==e.tradingDay)throw Error(`Live \u98CE\u63A7 TradingDay \u56DE\u9000: ${this.live.tradingDay}/${e.tradingDay}`);let t=this.live,r=Me(e.tradingDay);for(let n of e.orders)this.addSnapshotOrder(r,n);for(let n of e.trades)this.addSnapshotTrade(r,n);t.orderIds=new Set([...t.orderIds,...r.orderIds]),t.cancelledOrderIds=new Set([...t.cancelledOrderIds,...r.cancelledOrderIds]),t.tradeIds=new Set([...t.tradeIds,...r.tradeIds]),sr(t.total,r.total);for(let[n,i]of r.instruments){let o=this.instrumentCounts(t,n);sr(o,i)}sr(t.total,Lo(t.instruments.values()));for(let[n,i]of r.duplicateAttempts)t.duplicateAttempts.set(n,Math.max(t.duplicateAttempts.get(n)??0,i));this.markDirty()}snapshot(){return{limits:{dailyLimits:{...this.settings.dailyLimits},duplicateOrderLimit:this.settings.duplicateOrderLimit},paper:this.modeSnapshot(this.paper),live:this.modeSnapshot(this.live)}}tradingDay(e){return this.mode(e).tradingDay}flush(){if(this.persistTimer?.(),this.persistTimer=null,!this.dirty||!this.stateStore)return;this.stateStore.write({paper:Nn(this.paper),live:Nn(this.live)}),this.dirty=!1}close({persist:e=!0}={}){if(e)this.flush();else this.persistTimer?.(),this.persistTimer=null}dailyFailure(e,t){let r=this.settings.dailyLimits,n=this.instrumentCounts(e,t),o=[[e.total.orders,r.totalOrderLimit,"\u5F53\u65E5\u5168\u5C40\u59D4\u6258","daily_total_order_limit"],[e.total.cancels,r.totalCancelLimit,"\u5F53\u65E5\u5168\u5C40\u64A4\u5355","daily_total_cancel_limit"],[e.total.trades,r.totalTradeLimit,"\u5F53\u65E5\u5168\u5C40\u6210\u4EA4","daily_total_trade_limit"],[n.orders,r.instrumentOrderLimit,`${t} \u5F53\u65E5\u59D4\u6258`,"daily_instrument_order_limit"],[n.cancels,r.instrumentCancelLimit,`${t} \u5F53\u65E5\u64A4\u5355`,"daily_instrument_cancel_limit"],[n.trades,r.instrumentTradeLimit,`${t} \u5F53\u65E5\u6210\u4EA4`,"daily_instrument_trade_limit"]].find(([s,a])=>s>=a);return o?{code:o[3],message:`${o[2]}\u8FBE\u5230\u4E0A\u9650 ${o[0]}/${o[1]}`}:null}addSnapshotOrder(e,t){if(t.identity.tradingDay!==e.tradingDay||e.orderIds.has(t.vtOrderId))return;if(e.orderIds.add(t.vtOrderId),this.increment(e,t.vtSymbol.toUpperCase(),"orders"),t.status==="cancelled")e.cancelledOrderIds.add(t.vtOrderId),this.increment(e,t.vtSymbol.toUpperCase(),"cancels");if(t.offset==="open"){let r=Fn({vtSymbol:t.vtSymbol,direction:t.direction,offset:t.offset,price:t.price,volume:t.volume});e.duplicateAttempts.set(r,(e.duplicateAttempts.get(r)??0)+1)}}addSnapshotTrade(e,t){if(t.tradingDay!==e.tradingDay||e.tradeIds.has(t.vtTradeId))return;e.tradeIds.add(t.vtTradeId),this.increment(e,t.vtSymbol.toUpperCase(),"trades")}increment(e,t,r){e.total[r]++,this.instrumentCounts(e,t)[r]++}instrumentCounts(e,t){let r=e.instruments.get(t);if(!r)r=ar(),e.instruments.set(t,r);return r}mode(e){return e==="paper"?this.paper:this.live}replaceMode(e,t){if(e==="paper")this.paper=t;else this.live=t}modeSnapshot(e){let t=0,r=0;for(let n of e.duplicateAttempts.values()){if(n>=2)t++;r=Math.max(r,n)}return{tradingDay:e.tradingDay,total:{...e.total},instruments:Object.fromEntries([...e.instruments.entries()].sort(([n],[i])=>n.localeCompare(i)).map(([n,i])=>[n,{...i}])),duplicateRequests:{trackedKeys:e.duplicateAttempts.size,repeatedKeys:t,maxAttempts:r,rejected:e.duplicateRejected}}}markDirty(){if(this.dirty=!0,!this.stateStore||this.persistTimer)return;this.persistTimer=this.schedule(()=>{this.persistTimer=null,this.flush()},this.persistDelayMs)}}var qn=1e5,Fo=1e5,qo=500;function cr(){return{longToday:0,longYesterday:0,shortToday:0,shortYesterday:0}}function B(e,t){return`${t}:${e}`}function Vn(e){return e!==null&&typeof e==="object"&&!Array.isArray(e)}function lr(e,t,r){if(e===null||typeof e==="string"||typeof e==="boolean")return;if(typeof e==="number"){if(!Number.isFinite(e))throw Error(`${t} \u5305\u542B\u975E\u6709\u9650\u6570\u5B57`);return}if(typeof e!=="object")throw Error(`${t} \u5305\u542B\u4E0D\u53EF\u5E8F\u5217\u5316\u7684 ${typeof e}`);if(r.has(e))throw Error(`${t} \u5305\u542B\u5FAA\u73AF\u5F15\u7528`);if(r.add(e),Array.isArray(e))for(let n=0;n<e.length;n++)lr(e[n],`${t}[${n}]`,r);else{let n=Object.getPrototypeOf(e);if(n!==Object.prototype&&n!==null)throw Error(`${t} \u5FC5\u987B\u662F\u666E\u901A\u5BF9\u8C61\u6216\u6570\u7EC4`);for(let[i,o]of Object.entries(e))lr(o,`${t}.${i}`,r)}r.delete(e)}function Un(e,t){return lr(e,t,new Set),JSON.parse(JSON.stringify(e))}function zn(e){return`${e.code}\x00${e.timeframe}\x00${e.barTime}`}function J(e){return e.longToday+e.longYesterday-e.shortToday-e.shortYesterday}function ur(e){if(!Vn(e))throw Error("\u7F3A\u5C11\u7B56\u7565\u5B9E\u4F8B\u914D\u7F6E");let{id:t,vtSymbol:r,setting:n}=e,i=Object.keys(e).find((o)=>o!=="id"&&o!=="vtSymbol"&&o!=="setting");if(i)throw Error(`\u7B56\u7565\u5B9E\u4F8B\u914D\u7F6E\u4E0D\u652F\u6301\u5B57\u6BB5 "${i}"`);if(typeof t!=="string"||!we.test(t))throw Error("\u7B56\u7565 id \u5FC5\u987B\u4E3A 1-64 \u4F4D\u5B57\u6BCD\u3001\u6570\u5B57\u3001\u70B9\u3001\u4E0B\u5212\u7EBF\u6216\u8FDE\u5B57\u7B26\uFF0C\u5E76\u4EE5\u5B57\u6BCD\u6216\u6570\u5B57\u5F00\u5934");if(typeof r!=="string")throw Error(`\u7B56\u7565 ${t} \u7F3A\u5C11 vtSymbol`);if(!Vn(n))throw Error(`\u7B56\u7565 ${t} \u7684 setting \u5FC5\u987B\u662F\u5BF9\u8C61`);return{id:t,vtSymbol:K(r).vtSymbol,setting:Un(n,`\u7B56\u7565 ${t} setting`)}}function Vo(){let e=nr(!0);return{getBars:async(t,r)=>{let n=xr(r.timeframe,r.count),i=await e.getLatestBars(t,"1min",n),o=ke(i,r.timeframe,r.count);if(o.selectedCount<r.count)throw Error(`\u5408\u7EA6 ${t} \u9884\u70ED\u6570\u636E\u4E0D\u8DB3\uFF1A\u9700\u8981 ${r.count} \u6839\u95ED\u5408 ${r.timeframe} Bar\uFF0C\u4EC5\u6709 ${o.availableCount} \u6839`);return o.bars},destroy:()=>e.destroy()}}class mr{strategies=new Map;instanceMap=new Map;orderOwners=new Map;terminalPaperOrders=new Set;liveOrders=new Map;liveTradeIds=new Set;pending=new Map;deps;cleanups=[];eventQueue=[];dispatching=!1;initializing=null;liveTradingDay="";timerCursorMs=null;eventTimeMs=null;tradeClaimContext=null;constructor(e={}){if(this.deps={createWarmupProvider:Vo,stateStore:new $e,live:null,paperExecution:null,recordTrade:null,orderRisk:new He,executionLimits:{maxOrderVolume:re.trading.maxOrderVolume,maxPosition:re.trading.maxPosition,maxActiveOpenOrders:re.trading.maxActiveOpenOrders},log:(t)=>console.log(t),now:Date.now,schedule:pt,createPaperSessionId:No,observe:()=>{},emitHook:null,...e},this.deps.live)this.cleanups.push(this.deps.live.onOrder((t)=>this.enqueue(()=>{this.deps.orderRisk.recordOrder("live",t,t.identity.tradingDay),this.handleLiveOrder(t)})),this.deps.live.onTrade((t)=>this.enqueue(()=>{this.deps.orderRisk.recordTrade("live",t),this.handleLiveTrade(t)})),this.deps.live.onOrderError((t)=>this.enqueue(()=>this.handleLiveError(t))),this.deps.live.onReconciled((t)=>this.handleLiveReconciled(t)),this.deps.live.onFault((t)=>this.enqueue(()=>this.handleLiveFault(t))))}prepare(e){if(e.mode!=="paper"&&e.mode!=="live")throw Error("\u7B56\u7565 mode \u5FC5\u987B\u662F paper \u6216 live");let t=ur(e.instance),r=K(t.vtSymbol),n=Se(e.definition,t.id,t.setting),i={id:t.id,name:n.ctor.name||t.id,ctor:n.ctor,instance:n.instance,runtime:n.runtime,vtSymbol:r.vtSymbol,instrumentID:r.instrumentID,setting:n.effectiveSetting,enabled:e.enabled??e.mode==="paper",mode:e.mode,sourcePath:e.sourcePath,hash:e.hash,artifact:e.artifact,loadedAt:e.loadedAt,inventory:cr(),orders:new Map,inited:!1,trading:!1,fault:null,expectedLivePos:null,expectedLiveInventory:null,tradingDay:"",stateTimer:null,warmupRequests:[],paperSessionId:this.deps.createPaperSessionId(),paperOrderCounter:0,paperTradeCounter:0,seenTrades:new Set,tradeVolumeByOrder:new Map,eventHandlers:{timer:new Set,trades:new Set}};return n.runtime.bindContext({ctaEngine:this,strategyName:t.id,vtSymbol:r.vtSymbol,mode:e.mode,setting:n.effectiveSetting}),this.assertLiveInstrumentOwner(i),this.instanceMap.set(n.instance,i),i}addRestored(e){let t=ur(e.instance),r=B(t.id,e.mode);if(this.strategies.has(r))throw Error(`\u7B56\u7565\u5B9E\u4F8B\u91CD\u590D: ${t.id} (${e.mode})`);let n=this.prepare(e);return this.strategies.set(r,n),n}assertStateCompatible(e){this.deps.stateStore.assertCompatible(e.id,e.mode,e.vtSymbol,e.ctor.variables??[])}async warmup(){for(let e of this.strategies.values())if(!e.inited)await this.warmupOne(e)}canInitialize(){return this.deps.live?.phase==="running"}async prepareMetadata(){for(let e of this.strategies.values())await this.prepareContractMetadata(e)}async preparePendingMetadata(e,t){await this.prepareContractMetadata(this.requirePending(e,t).running)}beginReplace(e){let t=ur(e.instance),r=B(t.id,e.mode),n=this.strategies.get(r);if(n?.trading)throw Error(`\u7B56\u7565 ${n.id} \u8FD0\u884C\u4E2D\uFF0C\u8BF7\u5148\u505C\u6B62\u518D\u66F4\u65B0`);if(n)this.assertOrdersSettled(n.id,n.mode);if(n&&n.vtSymbol!==t.vtSymbol)throw Error(`\u7B56\u7565 ${n.id} \u5DF2\u7ED1\u5B9A ${n.vtSymbol}\uFF0C\u66F4\u6362\u5408\u7EA6\u5FC5\u987B\u4F7F\u7528\u65B0\u7684\u5B9E\u4F8B ID`);let i=this.prepare(e);if(this.pending.has(r))throw this.instanceMap.delete(i.instance),Error(`\u7B56\u7565 ${i.id} (${i.mode}) \u5DF2\u5728\u52A0\u8F7D\u4E2D`);return this.pending.set(r,{running:i,events:[],replayedBars:new Set,overflowed:!1,warmed:!1}),i}async warmupPending(e,t,{restoreState:r=!0}={}){let n=this.requirePending(e,t);if(await this.warmupOne(n.running,n.replayedBars,!1,r),n.warmed=!0,n.overflowed)throw Error(`\u7B56\u7565 ${e} \u521D\u59CB\u5316\u671F\u95F4\u7F13\u5B58\u884C\u60C5\u8D85\u8FC7 ${qn} \u6761`)}async commitPending(e,t){let r=this.requirePending(e,t),n=B(e,r.running.mode);if(!r.warmed)throw Error(`\u7B56\u7565 ${e} \u5C1A\u672A\u5B8C\u6210\u521D\u59CB\u5316`);if(r.overflowed)throw Error(`\u7B56\u7565 ${e} \u521D\u59CB\u5316\u671F\u95F4\u7F13\u5B58\u6EA2\u51FA`);if(this.drainPending(r),r.running.fault)throw Error(`\u7B56\u7565 ${e} \u521D\u59CB\u5316\u671F\u95F4\u5F02\u5E38: ${r.running.fault}`);this.saveState(r.running);let i=this.strategies.get(n);if(this.strategies.set(n,r.running),this.pending.delete(n),i)await this.dispose(i,!1);return r.running}async commitPendingUninitialized(e,t){let r=this.requirePending(e,t),n=B(e,r.running.mode);if(r.warmed)throw Error(`\u7B56\u7565 ${e} \u5DF2\u521D\u59CB\u5316\uFF0C\u4E0D\u80FD\u6309\u7B49\u5F85\u72B6\u6001\u63D0\u4EA4`);r.events.length=0;let i=this.strategies.get(n);if(this.strategies.set(n,r.running),this.pending.delete(n),i)await this.dispose(i,!1);return r.running}async abortPending(e,t){let r=this.findPending(e,t);if(!r)return;let n=B(e,r.running.mode);this.pending.delete(n),await this.dispose(r.running,!1)}async start(e,t){let r=this.requireRunning(e,t);if(r.trading)return r;try{if(!r.inited||r.fault)throw Error(`\u7B56\u7565 ${e} \u672A\u5B8C\u6210\u521D\u59CB\u5316${r.fault?`: ${r.fault}`:""}`);if(await this.prepareContractMetadata(r),r.mode==="live")await this.prepareLive(r);try{this.invokeStrategySync(r,"onStart",()=>r.instance.onStart())}catch(n){throw this.failStrategy(r,"onStart",n),n}r.trading=!0,this.syncFrameworkState(r);try{this.saveState(r)}catch(n){throw this.failStrategy(r,"state",n),n}return this.writeLog(r.instance,`started mode=${r.mode}`),this.publishHook("strategy.started",this.strategyIdentity(r)),r}catch(n){throw this.publishHook("strategy.start_failed",{...this.strategyIdentity(r),reason:n instanceof Error?n.message:String(n)}),n}}async startAll(){for(let e of this.strategies.values()){if(!e.enabled)continue;try{await this.start(e.id,e.mode)}catch(t){let r=t instanceof Error?t.message:String(t);console.error(`[cta] ${e.id} \u542F\u52A8\u5931\u8D25: ${r}`)}}}async stop(e,{cancelOrders:t=!1},r){let n=this.requireRunning(e,r);if(n.trading){n.trading=!1,this.syncFrameworkState(n);try{this.invokeStrategySync(n,"onStop",()=>n.instance.onStop())}catch(i){this.failStrategy(n,"onStop",i)}if(this.trySaveState(n),this.writeLog(n.instance,"stopped"),!n.fault)this.publishHook("strategy.stopped",this.strategyIdentity(n))}if(this.syncFrameworkState(n),t)this.cancelAllDirect(n);else{let i=[...n.orders.values()].filter(w).length;if(i>0){let o=this.retainedOrdersMessage(i);this.writeLog(n.instance,o),this.publishHook("strategy.orders_retained",{...this.strategyIdentity(n),activeOrders:i,reason:o})}}return n}async stopAll(e={}){for(let t of this.strategies.values())await this.stop(t.id,e,t.mode)}cancelStrategyOrder(e,t,r){let n=this.requireRunning(e,r),i=n.orders.get(t);if(!i)throw Error(`\u59D4\u6258\u4E0D\u5C5E\u4E8E\u7B56\u7565 ${e}: ${t}`);if(!w(i))return;if(n.mode==="paper")this.cancelOrder(n.instance,t);else{if(!this.deps.live)throw Error("\u5B9E\u76D8\u901A\u9053\u4E0D\u53EF\u7528");this.deps.live.cancelOrder(t)}}cancelPaperOrder(e){if(this.terminalPaperOrders.has(e))return{vtOrderId:e,mode:"paper",result:"terminal"};let t=this.orderOwners.get(e);if(!t||t.mode!=="paper")return null;let r=t.orders.get(e);if(!r)return null;if(!w(r))return{vtOrderId:e,mode:"paper",result:"terminal"};return this.cancelStrategyOrder(t.id,e,t.mode),{vtOrderId:e,mode:"paper",result:"requested"}}async remove(e,t,{clearState:r=!1}={}){let n=this.findRunning(e,t);if(!n)return null;if(await this.stop(n.id,{},n.mode),this.assertOrdersSettled(n.id,n.mode),this.strategies.delete(B(n.id,n.mode)),await this.dispose(n,!r),r)this.deps.stateStore.remove(n.id,n.mode);return n}assertOrdersSettled(e,t){let r=this.requireRunning(e,t);if(r.orders.size>0)throw Error(`\u7B56\u7565 ${e} \u4ECD\u6709 ${r.orders.size} \u7B14\u59D4\u6258\u6216\u6210\u4EA4\u56DE\u62A5\u672A\u5B8C\u6210\uFF0C\u8BF7\u7B49\u5F85\u56DE\u62A5\u6536\u9F50\u540E\u91CD\u8BD5`)}async assertResettable(e,t){let r=this.requireRunning(e,t);if(r.trading||r.enabled)throw Error(`\u7B56\u7565 ${r.id}@${r.mode} \u5C1A\u672A\u505C\u6B62\uFF0C\u8BF7\u5148\u6267\u884C vibek strategy stop ${r.id}@${r.mode}`);if(this.assertOrdersSettled(r.id,r.mode),r.mode!=="live")return r;let n=this.deps.live;if(!n||n.phase!=="running")throw Error("TD \u672A\u8FD0\u884C\uFF0C\u65E0\u6CD5\u91CD\u7F6E Live \u7B56\u7565\u72B6\u6001");let o=(await n.queryOrders(r.instrumentID)).filter(U);if(o.length>0)throw Error(`\u5238\u5546\u5B58\u5728 ${o.length} \u7B14\u6D3B\u52A8\u59D4\u6258\uFF0C\u8BF7\u5148\u4EBA\u5DE5\u5904\u7406`);let s=await n.queryPositions(r.instrumentID);if(s.phase!=="running")throw Error("\u67E5\u8BE2\u5B9E\u76D8\u6301\u4ED3\u5931\u8D25");let a=this.inventoryFromBroker(s.positions,r.instrumentID),d=this.sidePositions(a);if(d.long!==0||d.short!==0)throw Error(`\u5408\u7EA6 ${r.instrumentID} \u4ECD\u6709\u5238\u5546\u6301\u4ED3 \u591A${d.long}/\u7A7A${d.short}\uFF0C\u4E0D\u80FD\u91CD\u7F6E\u672C\u5730\u72B6\u6001`);return r}async close({persist:e=!0}={}){if(e)await this.stopAll({cancelOrders:!0});let t=[...this.strategies.values()],r=[...this.pending.values()].map((n)=>n.running);this.strategies.clear(),this.pending.clear();for(let n of[...t,...r])await this.dispose(n,e);for(let n of this.cleanups.splice(0))n();this.deps.orderRisk.close({persist:e}),this.liveOrders.clear(),this.terminalPaperOrders.clear(),this.liveTradeIds.clear(),this.tradeClaimContext=null,this.timerCursorMs=null,this.eventTimeMs=null}has(e,t){return this.strategies.has(B(e,t))}resolve(e,t){return this.requireRunning(e,t)}setEnabled(e,t,r){let n=this.requireRunning(e,r);if(n.enabled===t)return n;return n.enabled=t,this.publishHook(t?"strategy.enabled":"strategy.disabled",this.strategyIdentity(n)),n}instruments(){return[...new Set([...this.strategies.values()].map((e)=>e.instrumentID))]}instrumentDeclarations(){return[...this.strategies.values()].map((e)=>this.declaration(e))}instrumentDeclarationsWithPending(e,t){let r=this.requirePending(e,t).running;return[...this.strategies.values()].map((n)=>this.declaration(n)).concat(this.declaration(r))}instrumentsWithPending(e,t){let r=this.requirePending(e,t).running;return[...new Set([...this.strategies.values()].map((n)=>n.instrumentID).concat(r.instrumentID))]}handleBar(e){for(let t of this.strategies.values())if(t.instrumentID===e.code&&t.inited)this.enqueue(()=>this.callStrategy(t,"onBar",()=>t.instance.onBar(e)));this.queuePending({kind:"bar",value:e},e.code)}handleTick(e){this.dispatchMarketEvent(e,[])}handleMarketEvent(e,t){this.dispatchMarketEvent(e,t)}handlePaperExternalTrade(e,t){if(e.type!=="order"||e.vtOrderId!==t.vtOrderId||e.vtSymbol!==t.vtSymbol||e.direction!==t.direction||e.offset!==t.offset||e.status!=="allTraded"||e.traded!==e.volume||t.volume!==e.volume)throw Error("\u5916\u90E8 Paper \u8BA2\u5355\u4E0E\u6210\u4EA4\u4E0D\u4E00\u81F4");let r={order:{...e},origin:"external",tradingDay:t.tradingDay,tradedVolume:t.volume,claimable:e.offset==="open",ownerId:null};this.enqueue(()=>{this.dispatchTrades("paper",{...t},{...e},"external",{observed:r,firstTrade:!0,allowPaper:!0})})}handleTimer(e){if(!Number.isFinite(e)||e<0)throw Error("Timer \u65F6\u95F4\u5FC5\u987B\u662F\u975E\u8D1F\u6709\u9650\u6570");let t=Math.floor(e/1000)*1000;if(this.timerCursorMs===null){this.timerCursorMs=t;return}if(t<this.timerCursorMs)throw Error("Timer \u65F6\u95F4\u4E0D\u80FD\u56DE\u9000");for(let r=this.timerCursorMs+1000;r<=t;r+=1000)this.dispatchTimer(r);this.timerCursorMs=t}setTimerClock(e){if(!Number.isFinite(e)||e<0)throw Error("Timer \u65F6\u95F4\u5FC5\u987B\u662F\u975E\u8D1F\u6709\u9650\u6570");this.timerCursorMs=Math.floor(e/1000)*1000}dispatchMarketEvent(e,t){let r=e.tradingDay??e.actionDay??"";this.deps.orderRisk.setTradingDay("paper",r);let n=new Map;for(let i of t){let o=n.get(i.code)??[];o.push(i),n.set(i.code,o)}for(let i of this.strategies.values()){if(!i.inited)continue;let o=i.instrumentID===e.code,s=n.get(i.instrumentID)??[];if(!o&&s.length===0)continue;this.enqueue(()=>{if(o&&i.mode==="paper")this.rollPaperDay(i,r),this.matchPaperOrders(i,e);for(let a of s){if(i.fault)break;this.callStrategy(i,"onBar",()=>i.instance.onBar(a))}if(o)this.callStrategy(i,"onTick",()=>i.instance.onTick(e))})}for(let i of t)this.queuePending({kind:"bar",value:i},i.code);this.queuePending({kind:"tick",value:e},e.code)}snapshot(e={}){return[...this.strategies.values()].map((t)=>{let r=[...t.orders.values()].filter(w).map((n)=>({...n,type:"order"}));return{id:t.id,name:t.name,sourcePath:t.sourcePath,hash:t.hash,loadedAt:t.loadedAt,mode:t.mode,vtSymbol:t.vtSymbol,instrumentID:t.instrumentID,setting:t.setting,enabled:t.enabled,inited:t.inited,trading:t.trading,pos:J(t.inventory),inventory:{...t.inventory},activeOrders:r.length,activeOrderDetails:r,warning:!t.trading&&r.length>0?this.retainedOrdersMessage(r.length):null,fault:t.fault,...e.variables?this.variablesSnapshot(t):{}}})}variablesSnapshot(e){try{return{variables:this.serializeVariables(e),variablesError:null}}catch(t){return{variables:null,variablesError:t instanceof Error?t.message:String(t)}}}riskSnapshot(){return this.deps.orderRisk.snapshot()}sendOrder(e,t,r,n,i){let o=this.requireInstance(e);if(!o.trading||o.fault)return[];if(!Number.isFinite(n)||n<=0||!Number.isInteger(i)||i<=0){let l=`price/volume \u975E\u6CD5 (${n}, ${i})`;return this.writeLog(e,`\u62D2\u7EDD\u59D4\u6258\uFF1A${l}`),this.emitOrderError(o,"invalidRequest",t,r,n,i,l),[]}if(i>this.deps.executionLimits.maxOrderVolume){let l=`\u6570\u91CF ${i} \u8D85\u8FC7\u5355\u7B14\u4E0A\u9650 ${this.deps.executionLimits.maxOrderVolume}`;return this.writeLog(e,`\u62D2\u7EDD\u59D4\u6258\uFF1A${l}`),this.emitRiskRejection(o,"max_order_volume",t,r,n,i,l),this.emitOrderError(o,"maxOrderVolume",t,r,n,i,l),[]}let s=this.resolveOrderParts(o,t,r,n,i);if(s.length===0)return[];if(r==="open"){if([...o.orders.values()].filter((f)=>f.offset==="open"&&w(f)).length>=this.deps.executionLimits.maxActiveOpenOrders){let f=`\u6D3B\u52A8\u5F00\u4ED3\u59D4\u6258\u8FBE\u5230\u4E0A\u9650 ${this.deps.executionLimits.maxActiveOpenOrders}`;return this.writeLog(e,`\u62D2\u7EDD\u5F00\u4ED3\uFF1A${f}`),this.emitRiskRejection(o,"max_active_open_orders",t,r,n,i,f),this.emitOrderError(o,"maxActiveOpenOrders",t,r,n,i,f),[]}}let a=this.roundPrice(o,n);if(!Number.isFinite(a)||a<=0){let l=`price/volume \u975E\u6CD5 (\u820D\u5165\u540E\u4EF7\u683C ${a}\uFF0C\u539F\u59CB ${n})`;return this.writeLog(e,`\u62D2\u7EDD\u59D4\u6258\uFF1A${l}`),this.emitOrderError(o,"invalidRequest",t,r,n,i,l),[]}let d=o.mode==="live"?this.liveTradingDay||o.tradingDay||this.deps.orderRisk.tradingDay("live"):o.tradingDay||this.deps.orderRisk.tradingDay("paper"),c=this.deps.orderRisk.checkOpenDetailed({mode:o.mode,tradingDay:d,vtSymbol:o.vtSymbol,direction:t,offset:r,price:a,volume:i});if(c)return this.writeLog(e,`\u62D2\u7EDD\u5F00\u4ED3\uFF1A${c.message}`),this.emitRiskRejection(o,c.code,t,r,a,i,c.message),this.emitOrderError(o,"riskRejected",t,r,n,i,c.message),[];let u=[];for(let l of s){let f=this.submitPhysical(o,t,l.offset,a,l.volume);if(f)u.push(f)}return u}cancelOrder(e,t){let r=this.requireInstance(e),n=r.orders.get(t);if(!n||!w(n))return;if(r.mode==="paper")this.deps.paperExecution?.onCancelRequested?.(Object.freeze({...n})),n.status="cancelled",n.statusMessage="paper cancelled",this.queueOrder(r,n);else try{this.deps.live?.cancelOrder(t)}catch(i){this.handleLiveError({vtOrderId:t,orderRef:t.slice(4),instrumentID:r.instrumentID,operation:"cancel",message:i instanceof Error?i.message:String(i)})}}cancelAll(e){this.cancelAllDirect(this.requireInstance(e))}liquidatePaper(e,t,r){let n=this.requireRunning(e,"paper");if(n.mode!=="paper")throw Error(`\u7B56\u7565 ${e} \u4E0D\u662F Paper \u6A21\u5F0F`);this.deps.orderRisk.setTradingDay("paper",t.tradingDay??t.actionDay??n.tradingDay);let i=n.trading;n.trading=!1,this.syncFrameworkState(n),this.cancelAllDirect(n);let o=[{direction:"short",offset:"closeYesterday",volume:n.inventory.longYesterday},{direction:"short",offset:"closeToday",volume:n.inventory.longToday},{direction:"long",offset:"closeYesterday",volume:n.inventory.shortYesterday},{direction:"long",offset:"closeToday",volume:n.inventory.shortToday}],s=[];for(let a of o){if(a.volume<=0)continue;let d=a.direction==="long"?t.askPrice1??t.lastPrice:t.bidPrice1??t.lastPrice,c={vtOrderId:`PAPERLIQ.${n.id}.${n.paperSessionId}.${++n.paperOrderCounter}`,vtSymbol:n.vtSymbol,direction:a.direction,offset:a.offset,price:d,volume:a.volume,traded:a.volume,status:"allTraded",statusMessage:r,datetime:t.datetime??this.deps.now()},u=this.paperFill(c,t,a.volume,"marginLiquidation");c.price=u.price,n.orders.set(c.vtOrderId,c),this.orderOwners.set(c.vtOrderId,n),this.emitOrder(n,c);let l={vtTradeId:`PAPERLIQTRADE.${n.id}.${n.paperSessionId}.${++n.paperTradeCounter}`,vtOrderId:c.vtOrderId,vtSymbol:n.vtSymbol,direction:a.direction,offset:a.offset,price:u.price,volume:a.volume,datetime:t.datetime??this.deps.now(),tradingDay:t.tradingDay??t.actionDay??""};this.deps.paperExecution?.onTrade?.(l,u,"marginLiquidation"),this.applyTrade(n,l),s.push(l)}if(i)try{this.invokeStrategySync(n,"onStop",()=>n.instance.onStop())}catch(a){this.failStrategy(n,"onStop",a)}return this.cancelAllDirect(n),this.syncFrameworkState(n),this.scheduleState(n,!0),this.writeLog(n.instance,`\u5F3A\u5236\u5E73\u4ED3\u5E76\u505C\u6B62: ${r}`),s}loadBars(e,t,r){let n=this.requireInitializing(e,"loadBars");if(!t||typeof t!=="object"||Array.isArray(t))throw Error("loadBars request \u5FC5\u987B\u662F\u5BF9\u8C61");if(!Z(t.timeframe))throw Error(`loadBars timeframe \u4E0D\u53D7\u652F\u6301: ${String(t.timeframe)}`);if(!Number.isInteger(t.count)||t.count<=0)throw Error("loadBars count \u5FC5\u987B\u4E3A\u6B63\u6574\u6570");if(n.warmupRequests.length>0)throw Error("\u6BCF\u4E2A\u7B56\u7565\u53EA\u80FD\u767B\u8BB0\u4E00\u4E2A loadBars \u8BF7\u6C42");n.warmupRequests.push({timeframe:t.timeframe,count:t.count,callback:r})}registerEvent(e,t,r){let n=this.requireInitializing(e,"registerEvent");if(t!=="timer"&&t!=="trades")throw Error(`\u4E0D\u652F\u6301\u7684\u7B56\u7565\u4E8B\u4EF6: ${String(t)}`);if(typeof r!=="function")throw Error("\u7B56\u7565\u4E8B\u4EF6 handler \u5FC5\u987B\u662F\u51FD\u6570");let i=n.eventHandlers[t];i.add(r);let o=!0;return()=>{if(!o)return;o=!1,i.delete(r)}}claimOrder(e,t){let r=this.requireInstance(e),n=this.tradeClaimContext;if(r.mode!=="live"&&!(r.mode==="paper"&&n?.allowPaper))return{ok:!1,reason:"\u53EA\u6709 Live \u7B56\u7565\u6216\u4EA4\u4E92\u56DE\u6D4B\u53EF\u4EE5\u8BA4\u9886\u5916\u90E8\u8BA2\u5355"};if(!r.inited||!r.trading||r.fault)return{ok:!1,reason:"\u7B56\u7565\u672A\u5904\u4E8E\u4EA4\u6613\u72B6\u6001"};if(!n||n.running!==r||n.trade.vtOrderId!==t)return{ok:!1,reason:"claimOrder \u53EA\u80FD\u5728\u5F53\u524D\u8BA2\u5355\u7684 trades \u4E8B\u4EF6\u4E2D\u8C03\u7528"};let{observed:i,trade:o}=n;if(i.ownerId!==null||this.orderOwners.has(t))return{ok:!1,reason:"\u8BA2\u5355\u5DF2\u7ECF\u5F52\u5C5E\u7B56\u7565"};let s=i.order;if(!s)return{ok:!1,reason:"\u6210\u4EA4\u5173\u8054\u7684\u8BA2\u5355\u4FE1\u606F\u5C1A\u672A\u5B8C\u6574"};if(!n.firstTrade)return{ok:!1,reason:"\u53EA\u80FD\u8BA4\u9886\u5916\u90E8\u8BA2\u5355\u7684\u9996\u7B14\u65B0\u6210\u4EA4"};if(i.origin!=="external"||s.offset!=="open"||o.offset!=="open")return{ok:!1,reason:"\u53EA\u80FD\u8BA4\u9886\u5916\u90E8\u5F00\u4ED3\u8BA2\u5355"};if(s.vtSymbol!==r.vtSymbol||o.vtSymbol!==r.vtSymbol)return{ok:!1,reason:"\u8BA2\u5355\u5408\u7EA6\u4E0E\u7B56\u7565\u4E0D\u4E00\u81F4"};if(s.direction!==o.direction||o.volume>s.volume||s.status==="rejected")return{ok:!1,reason:"\u8BA2\u5355\u4E0E\u6210\u4EA4\u4FE1\u606F\u4E0D\u4E00\u81F4"};if(r.orders.size>0||Object.values(r.inventory).some((d)=>d!==0))return{ok:!1,reason:"\u7B56\u7565\u5DF2\u6709\u6301\u4ED3\u6216\u672A\u5B8C\u6210\u7684\u8BA2\u5355"};if(r.mode==="live")this.rollLiveDay(r,o.tradingDay);else this.rollPaperDay(r,o.tradingDay);let a={...s,traded:Math.max(s.traded,o.volume)};return i.ownerId=r.id,r.orders.set(t,a),this.orderOwners.set(t,r),this.queueOrder(r,a),this.applyTrade(r,{...o},!0,!1),this.writeLog(r.instance,`claimed external order ${t} on trade ${o.vtTradeId}`),{ok:!0}}writeLog(e,t){this.deps.log(`[cta:${e.strategyName}:${e.mode}] ${t}`)}emitHook(e,t,r){let n=this.requireInstance(e),i=this.eventTimeMs??this.deps.now(),o=er("strategy.event",{...this.strategyIdentity(n),name:t,data:r});fe({type:"hook",id:"00000000-0000-4000-8000-000000000000",event:"strategy.event",account:"a".repeat(64),occurredAt:i,payload:o});try{this.deps.emitHook?.("strategy.event",o,i)}catch(s){this.writeLog(e,`Hook \u6295\u9012\u5931\u8D25 name=${o.name}: ${s instanceof Error?s.message:String(s)}`)}}getCurrentTime(e){return this.requireInstance(e),this.eventTimeMs??this.deps.now()}getContract(e){let t=this.requireInstance(e),r=t.vtSymbol.split(".")[1],n=this.deps.live?.getInstrument(t.instrumentID);if(!n)throw Error(`\u5408\u7EA6 ${t.vtSymbol} Contract \u5C1A\u672A\u51C6\u5907`);if(n.instrumentID.toUpperCase()!==t.instrumentID)throw Error(`\u5408\u7EA6\u4EE3\u7801\u4E0D\u4E00\u81F4\uFF1A\u7B56\u7565 ${t.instrumentID}\uFF0C\u5143\u6570\u636E ${n.instrumentID}`);if(n.exchangeID.toUpperCase()!==r)throw Error(`\u5408\u7EA6\u4EA4\u6613\u6240\u4E0D\u4E00\u81F4\uFF1A\u7B56\u7565 ${r}\uFF0C\u5143\u6570\u636E ${n.exchangeID}`);if(!Number.isFinite(n.priceTick)||n.priceTick<=0||!Number.isSafeInteger(n.volumeMultiple)||n.volumeMultiple<=0||!Number.isSafeInteger(n.minLimitOrderVolume)||n.minLimitOrderVolume<=0||!Number.isSafeInteger(n.maxLimitOrderVolume)||n.maxLimitOrderVolume<n.minLimitOrderVolume||!Number.isFinite(n.longMarginRatio)||n.longMarginRatio<0||!Number.isFinite(n.shortMarginRatio)||n.shortMarginRatio<0)throw Error(`\u5408\u7EA6\u89C4\u683C\u975E\u6CD5: ${t.vtSymbol}`);return Object.freeze({vtSymbol:`${n.instrumentID}.${n.exchangeID}`.toUpperCase(),instrumentID:n.instrumentID.toUpperCase(),exchangeID:n.exchangeID.toUpperCase(),productID:n.productID.toUpperCase(),name:n.instrumentName,priceTick:n.priceTick,size:n.volumeMultiple,minOrderVolume:n.minLimitOrderVolume,maxOrderVolume:n.maxLimitOrderVolume,longMarginRatio:n.longMarginRatio,shortMarginRatio:n.shortMarginRatio,isTrading:n.isTrading===1})}getCommission(e){let t=this.requireInstance(e),r=t.vtSymbol.split(".")[1],n=this.deps.live?.getCommission(t.instrumentID,r);if(!n)throw Error(`\u5408\u7EA6 ${t.vtSymbol} Commission \u5C1A\u672A\u51C6\u5907`);let i=this.getContract(e);if(n.instrumentID.toUpperCase()!==t.instrumentID&&n.instrumentID.toUpperCase()!==i.productID||n.exchangeID&&n.exchangeID.toUpperCase()!==r)throw Error(`\u624B\u7EED\u8D39\u5408\u7EA6\u4E0D\u4E00\u81F4: ${t.vtSymbol}`);if([n.openRatioByMoney,n.openRatioByVolume,n.closeRatioByMoney,n.closeRatioByVolume,n.closeTodayRatioByMoney,n.closeTodayRatioByVolume].some((o)=>!Number.isFinite(o)||o<0))throw Error(`\u624B\u7EED\u8D39\u7387\u975E\u6CD5: ${t.vtSymbol}`);return Object.freeze({open:Object.freeze({ratioByMoney:n.openRatioByMoney,perLot:n.openRatioByVolume}),close:Object.freeze({ratioByMoney:n.closeRatioByMoney,perLot:n.closeRatioByVolume}),closeToday:Object.freeze({ratioByMoney:n.closeTodayRatioByMoney,perLot:n.closeTodayRatioByVolume})})}getPriceTick(e){return this.getContract(e).priceTick}getSize(e){return this.getContract(e).size}async warmupOne(e,t,r=!0,n=!0){e.warmupRequests=[],this.clearEventHandlers(e),e.inited=!1,e.trading=!1,this.syncFrameworkState(e),await this.prepareContractMetadata(e),this.initializing=e;try{this.invokeStrategySync(e,"onInit",()=>e.instance.onInit())}catch(i){throw Error(`\u7B56\u7565 ${e.id} onInit \u5931\u8D25: ${i instanceof Error?i.message:String(i)}`)}finally{this.initializing=null}if(e.warmupRequests.length>0){let i=this.deps.createWarmupProvider();try{for(let o of e.warmupRequests){let s={timeframe:o.timeframe,count:o.count},a=await i.getBars(e.instrumentID,s),d=Et(a,o.timeframe);if(d<o.count)throw Error(`\u5408\u7EA6 ${e.instrumentID} \u9884\u70ED\u6570\u636E\u4E0D\u5B8C\u6574\uFF1A\u9700\u8981 ${o.count} \u6839\u95ED\u5408 ${o.timeframe} Bar\uFF0C\u5B9E\u9645 ${d} \u6839`);for(let c of a)t?.add(zn(c)),this.invokeStrategySync(e,"loadBars callback",()=>o.callback(c));this.writeLog(e.instance,`loadBars ${d} ${o.timeframe} bars / ${a.length} source 1min bars`)}}catch(o){throw Error(`\u7B56\u7565 ${e.id} \u521D\u59CB\u5316\u6570\u636E\u5931\u8D25: ${o instanceof Error?o.message:String(o)}`)}finally{i.destroy()}}if(n)this.restoreState(e);if(this.serializeVariables(e),e.inited=!0,this.syncFrameworkState(e),r)this.saveState(e)}restoreState(e){let t=this.deps.stateStore.read(e.id,e.mode);if(this.observe(e,{type:"state",operation:"read",value:t?{pos:t.pos,inventory:{...t.inventory},variables:structuredClone(t.variables),tradingDay:t.tradingDay}:null}),!t)return;if(t.strategyId!==e.id||t.mode!==e.mode)throw Error(`\u7B56\u7565 ${e.id} \u72B6\u6001\u8EAB\u4EFD\u4E0D\u5339\u914D`);if(t.vtSymbol!==e.vtSymbol)throw Error(`\u7B56\u7565 ${e.id} \u7684\u72B6\u6001\u5C5E\u4E8E ${t.vtSymbol}\uFF0C\u4E0D\u80FD\u6062\u590D\u5230 ${e.vtSymbol}\uFF1B\u8BF7\u4F7F\u7528\u65B0\u7684\u5B9E\u4F8B ID`);if(e.runtime.restoreVariables(t.variables),e.expectedLivePos=t.pos,e.tradingDay=t.tradingDay,e.mode==="paper")e.inventory=t.inventory,this.syncFrameworkState(e);else e.inventory=t.inventory,e.expectedLiveInventory={...e.inventory},this.syncFrameworkState(e)}async prepareLive(e){let t=this.deps.live;if(!t||t.phase!=="running")throw Error("TD \u672A\u8FD0\u884C\uFF0C\u65E0\u6CD5\u542F\u52A8 Live \u7B56\u7565");let r=e.vtSymbol.split(".")[1],n=await t.prepareInstrument(e.instrumentID,r);if(n.exchangeID.toUpperCase()!==r)throw Error(`\u5408\u7EA6\u4EA4\u6613\u6240\u4E0D\u4E00\u81F4\uFF1A\u7B56\u7565 ${r}\uFF0CCTP ${n.exchangeID}`);let i=await t.queryOrders(e.instrumentID);for(let u of i)this.observeLiveOrder(this.orderDataFromBroker(u),u.identity.tradingDay,!1);let o=i.filter(U);if(o.length>0)throw Error(`\u5238\u5546\u5B58\u5728 ${o.length} \u7B14\u6D3B\u52A8\u59D4\u6258\uFF0C\u8BF7\u5148\u4EBA\u5DE5\u5904\u7406`);let s=await t.queryPositions(e.instrumentID);if(s.phase!=="running")throw Error("\u67E5\u8BE2\u5B9E\u76D8\u6301\u4ED3\u5931\u8D25");let a=this.inventoryFromBroker(s.positions,e.instrumentID),d=J(a),c=this.sidePositions(a);if(e.expectedLivePos===null&&(c.long!==0||c.short!==0))throw Error(`\u5408\u7EA6 ${e.instrumentID} \u5DF2\u6709\u5238\u5546\u6301\u4ED3 \u591A${c.long}/\u7A7A${c.short}\uFF0C\u65B0\u7B56\u7565\u62D2\u7EDD\u8BA4\u9886`);if(e.expectedLivePos!==null&&e.expectedLivePos!==d)throw Error(`\u6301\u4ED3\u4E0D\u4E00\u81F4\uFF1A\u672C\u5730 ${e.expectedLivePos}\uFF0C\u5238\u5546 ${d}`);if(e.expectedLiveInventory){let u=this.sidePositions(e.expectedLiveInventory);if(u.long!==c.long||u.short!==c.short)throw Error(`\u6301\u4ED3\u4E0D\u4E00\u81F4\uFF1A\u672C\u5730\u591A${u.long}/\u7A7A${u.short}\uFF0C\u5238\u5546\u591A${c.long}/\u7A7A${c.short}`)}e.inventory=a,e.expectedLivePos=d,e.expectedLiveInventory={...a},e.tradingDay=this.liveTradingDay||s.positions.find((u)=>u.instrumentID===e.instrumentID)?.tradingDay||e.tradingDay,this.syncFrameworkState(e)}async prepareContractMetadata(e){let t=this.deps.live;if(!t||t.phase!=="running")throw Error(`TD \u672A\u8FD0\u884C\uFF0C\u65E0\u6CD5\u521D\u59CB\u5316\u7B56\u7565 ${e.id}`);let r=e.vtSymbol.split(".")[1],n=await t.prepareInstrument(e.instrumentID,r);if(n.exchangeID.toUpperCase()!==r)throw Error(`\u5408\u7EA6\u4EA4\u6613\u6240\u4E0D\u4E00\u81F4\uFF1A\u7B56\u7565 ${r}\uFF0CCTP ${n.exchangeID}`);if(tt(n.exchangeID,n.productID),!this.getContract(e.instance).isTrading)throw Error(`\u5408\u7EA6\u5F53\u524D\u4E0D\u53EF\u4EA4\u6613: ${e.vtSymbol}`);await t.prepareCommission(e.instrumentID,r)}declaration(e){let t=e.vtSymbol.split(".")[1];return{instrumentID:e.instrumentID,exchangeID:t,vtSymbol:e.vtSymbol}}inventoryFromBroker(e,t){let r=cr();for(let n of e){if(n.instrumentID.toUpperCase()!==t.toUpperCase())continue;if(n.hedgeFlag!=="1"&&n.volume!==0)throw Error(`\u6682\u4E0D\u652F\u6301\u975E\u6295\u673A\u6301\u4ED3: ${n.instrumentID}/${n.hedgeFlag}`);if(!Number.isInteger(n.todayVolume)||n.todayVolume<0||!Number.isInteger(n.yesterdayVolume)||n.yesterdayVolume<0||n.todayVolume+n.yesterdayVolume!==n.volume)throw Error(`\u5238\u5546\u6301\u4ED3\u6570\u636E\u975E\u6CD5: ${n.instrumentID}`);if(n.direction==="long")r.longToday+=n.todayVolume,r.longYesterday+=n.yesterdayVolume;else r.shortToday+=n.todayVolume,r.shortYesterday+=n.yesterdayVolume}return r}sidePositions(e){return{long:e.longToday+e.longYesterday,short:e.shortToday+e.shortYesterday}}resolveOrderParts(e,t,r,n,i){if(r==="open"){let c=t==="long"?e.inventory.longToday+e.inventory.longYesterday:e.inventory.shortToday+e.inventory.shortYesterday,u=[...e.orders.values()].filter((l)=>l.offset==="open"&&l.direction===t).reduce((l,f)=>l+this.unsettledOrderVolume(e,f),0);if(c+u+i>this.deps.executionLimits.maxPosition){let l=`\u9884\u8BA1\u6301\u4ED3 ${c+u+i} \u8D85\u8FC7\u4E0A\u9650 ${this.deps.executionLimits.maxPosition}`;return this.writeLog(e.instance,`\u62D2\u7EDD\u5F00\u4ED3\uFF1A${l}`),this.emitRiskRejection(e,"max_position",t,r,n,i,l),this.emitOrderError(e,"maxPosition",t,r,n,i,l),[]}return[{offset:r,volume:i}]}let o=this.availableClose(e,t);if(r==="closeToday"){if(i>o.today)return this.rejectInsufficientClose(e,t,r,n,i,o);return[{offset:r,volume:i}]}if(r==="closeYesterday"){if(i>o.yesterday)return this.rejectInsufficientClose(e,t,r,n,i,o);return[{offset:r,volume:i}]}if(i>o.today+o.yesterday)return this.rejectInsufficientClose(e,t,r,n,i,o);if(!Pr(e.vtSymbol))return[{offset:"close",volume:i}];let s=[],a=Math.min(i,o.yesterday);if(a>0)s.push({offset:"closeYesterday",volume:a});let d=i-a;if(d>0)s.push({offset:"closeToday",volume:d});return s}rejectInsufficientClose(e,t,r,n,i,o){let s=`\u8BF7\u6C42 ${i}\uFF0C\u53EF\u7528\u4ECA ${o.today}/\u6628 ${o.yesterday}`;return this.writeLog(e.instance,`\u62D2\u7EDD\u5E73\u4ED3\uFF1A${s}`),this.emitOrderError(e,"insufficientPosition",t,r,n,i,s),[]}availableClose(e,t){let r=t==="short"?e.inventory.longToday:e.inventory.shortToday,n=t==="short"?e.inventory.longYesterday:e.inventory.shortYesterday,i=0;for(let s of e.orders.values()){if(s.direction!==t||s.offset==="open")continue;let a=this.unsettledOrderVolume(e,s);if(a<=0)continue;if(s.offset==="closeToday")r-=a;else if(s.offset==="closeYesterday")n-=a;else i+=a}r=Math.max(0,r),n=Math.max(0,n);let o=Math.min(n,i);return n-=o,r=Math.max(0,r-(i-o)),{today:r,yesterday:n}}unsettledOrderVolume(e,t){let r=e.tradeVolumeByOrder.get(t.vtOrderId)??0,n=w(t)?t.volume:t.traded;return Math.max(0,n-r)}submitPhysical(e,t,r,n,i){let o;if(e.mode==="paper")o=`PAPER.${e.id}.${e.paperSessionId}.${++e.paperOrderCounter}`;else{let a=this.deps.live;if(!a)return this.emitOrderError(e,"submitFailed",t,r,n,i,"\u5B9E\u76D8\u901A\u9053\u4E0D\u53EF\u7528"),null;try{o=a.submitOrder({strategyId:e.id,instrumentID:e.instrumentID,direction:t==="long"?"buy":"sell",offsetFlag:r,price:n,volume:i}).vtOrderId}catch(d){let c=d instanceof Error?d.message:String(d);return this.writeLog(e.instance,`\u5B9E\u76D8\u62A5\u5355\u5931\u8D25: ${c}`),this.emitOrderError(e,"submitFailed",t,r,n,i,c),null}}let s={vtOrderId:o,vtSymbol:e.vtSymbol,direction:t,offset:r,price:n,volume:i,traded:0,status:"submitting",statusMessage:"",datetime:this.eventTimeMs??this.deps.now()};if(e.mode==="paper"){let a=this.deps.paperExecution?.acceptOrder?.(s)??{ok:!0};if(!a.ok)return this.writeLog(e.instance,`\u62D2\u7EDD\u59D4\u6258\uFF1A${a.reason}`),this.emitOrderError(e,"paperRejected",t,r,n,i,a.reason),null}if(e.orders.set(o,s),this.orderOwners.set(o,e),e.mode==="live"){let a=this.observeLiveOrder(s,this.liveTradingDay||e.tradingDay,!1);a.origin="strategy",a.ownerId=e.id}if(this.deps.orderRisk.recordOrder(e.mode,s,e.tradingDay),e.mode==="paper")this.deps.paperExecution?.onOrderSubmitted?.(Object.freeze({...s}));if(this.queueOrder(e,s),e.mode==="paper")this.enqueue(()=>{if(s.status!=="submitting")return;s.status="notTraded",this.emitOrder(e,s)});return this.scheduleState(e),o}matchPaperOrders(e,t){for(let r of[...e.orders.values()]){if(r.status!=="notTraded")continue;let n=r.direction==="long",i=n?t.askPrice1:t.bidPrice1,o=n?t.askVolume1:t.bidVolume1;if(i===void 0||!Number.isFinite(i)||i<=0)continue;if(o!==void 0&&(!Number.isFinite(o)||o<=0))continue;if(n?r.price<i:r.price>i)continue;let s=r.volume-r.traded,a=this.paperFill(r,t,s,"strategy");r.traded=r.volume,r.status="allTraded",r.statusMessage="paper matched",this.emitOrder(e,r);let d={vtTradeId:`PAPERTRADE.${e.id}.${e.paperSessionId}.${++e.paperTradeCounter}`,vtOrderId:r.vtOrderId,vtSymbol:e.vtSymbol,direction:r.direction,offset:r.offset,price:a.price,volume:s,datetime:t.datetime??this.deps.now(),tradingDay:t.tradingDay??t.actionDay??""};this.deps.paperExecution?.onTrade?.(d,a,"strategy"),this.applyTrade(e,d)}}handleLiveOrder(e){let t=e.vtOrderId;this.observeLiveOrder(this.orderDataFromBroker(e),e.identity.tradingDay);let r=this.orderOwners.get(t);if(!r||r.mode!=="live")return;let n=r.orders.get(t);if(!n)return;n.price=e.price,n.volume=e.volume,n.traded=e.traded,n.status=e.status,n.statusMessage=e.statusMessage,this.emitOrder(r,n),this.scheduleState(r,!0)}observeLiveOrder(e,t,r=!0){let n=this.liveOrders.get(e.vtOrderId);if(!n)n={order:null,origin:"external",tradingDay:t,tradedVolume:0,claimable:r,ownerId:null},this.liveOrders.set(e.vtOrderId,n);return n.order={...e,type:"order"},n.claimable&&=r,n}orderDataFromBroker(e){return{type:"order",vtOrderId:e.vtOrderId,vtSymbol:e.vtSymbol,direction:e.direction,offset:e.offset,price:e.price,volume:e.volume,traded:e.traded,status:e.status,statusMessage:e.statusMessage,datetime:e.datetime}}handleLiveTrade(e){if(!this.rememberTradeId(this.liveTradeIds,e.vtTradeId))return;let t=e.vtOrderId,r=this.orderOwners.get(t),n=this.liveOrders.get(t);if(!n)n={order:null,origin:"external",tradingDay:e.tradingDay,tradedVolume:0,claimable:!1,ownerId:null},this.liveOrders.set(t,n);let i=n.claimable&&n.tradedVolume===0&&this.deps.live?.phase==="running"&&(!this.liveTradingDay||e.tradingDay===this.liveTradingDay);n.tradedVolume+=e.volume,n.claimable=!1;let o={vtTradeId:e.vtTradeId,vtOrderId:t,vtSymbol:e.vtSymbol,direction:e.direction,offset:e.offset,price:e.price,volume:e.volume,datetime:e.datetime,tradingDay:e.tradingDay};if(r?.mode==="live")this.rollLiveDay(r,e.tradingDay),this.applyTrade(r,o);this.dispatchTrades("live",o,n.order,n.origin,{observed:n,firstTrade:i,allowPaper:!1})}handleLiveError(e){let t=this.orderOwners.get(e.vtOrderId);if(!t)return;let r=t.orders.get(e.vtOrderId);if(!r||!w(r))return;if(e.operation==="cancel"){r.statusMessage=`\u64A4\u5355\u5931\u8D25: ${e.message}`,this.emitOrder(t,r),this.scheduleState(t,!0);return}r.status="rejected",r.statusMessage=e.message,this.emitOrder(t,r),this.scheduleState(t,!0)}handleLiveReconciled(e){this.deps.orderRisk.reconcileLive(e),this.liveTradingDay=e.tradingDay;for(let[o,s]of this.liveOrders)if(s.tradingDay<e.tradingDay&&!this.orderOwners.has(o))this.liveOrders.delete(o);for(let o of e.orders)this.observeLiveOrder(this.orderDataFromBroker(o),o.identity.tradingDay,!1);for(let o of e.trades){if(!this.rememberTradeId(this.liveTradeIds,o.vtTradeId))continue;let s=this.liveOrders.get(o.vtOrderId);if(s)s.tradedVolume+=o.volume}if(e.reason!=="reconnect")return;let t=[...this.strategies.values()].filter((o)=>o.mode==="live"&&o.trading);if(t.length===0)return;let r=new Map;for(let o of t){let s=r.get(o.instrumentID)??[];s.push(o),r.set(o.instrumentID,s)}let n=new Map(e.orders.map((o)=>[o.vtOrderId,o]));for(let o of e.orders){if(!U(o)||!r.has(o.instrumentID))continue;let s=this.orderOwners.get(o.vtOrderId);if(!s||!s.trading)throw Error(`\u6062\u590D\u53D1\u73B0\u672A\u5F52\u5C5E\u7684\u6D3B\u52A8\u59D4\u6258: ${o.vtOrderId}`)}for(let o of t)for(let s of o.orders.values())if(w(s)&&!n.has(s.vtOrderId))throw Error(`\u672C\u5730\u6D3B\u52A8\u59D4\u6258\u672A\u51FA\u73B0\u5728\u5238\u5546\u5FEB\u7167: ${s.vtOrderId}`);let i=new Map;for(let o of t)i.set(o,this.inventoryOnTradingDay(o,e.tradingDay));for(let[o,s]of r){let a=this.inventoryFromBroker(e.positions,o),d=s.reduce((c,u)=>{let l=i.get(u);return{longToday:c.longToday+l.longToday,longYesterday:c.longYesterday+l.longYesterday,shortToday:c.shortToday+l.shortToday,shortYesterday:c.shortYesterday+l.shortYesterday}},cr());if(!this.sameInventory(a,d))throw Error(`\u6062\u590D\u6301\u4ED3\u4E0D\u4E00\u81F4 ${o}: \u672C\u5730\u4ECA/\u6628 \u591A${d.longToday}/${d.longYesterday}`+` \u7A7A${d.shortToday}/${d.shortYesterday}\uFF0C\u5238\u5546\u4ECA/\u6628 \u591A${a.longToday}/${a.longYesterday}`+` \u7A7A${a.shortToday}/${a.shortYesterday}`)}for(let[o,s]of i)o.inventory=s,o.expectedLivePos=J(s),o.expectedLiveInventory={...s},o.tradingDay=e.tradingDay,this.syncFrameworkState(o),this.scheduleState(o,!0)}inventoryOnTradingDay(e,t){if(e.tradingDay&&e.tradingDay>t)throw Error(`\u6062\u590D TradingDay \u56DE\u9000: ${e.tradingDay}/${t}`);let r={...e.inventory};if(e.tradingDay&&e.tradingDay!==t)r.longYesterday+=r.longToday,r.longToday=0,r.shortYesterday+=r.shortToday,r.shortToday=0;return r}sameInventory(e,t){return e.longToday===t.longToday&&e.longYesterday===t.longYesterday&&e.shortToday===t.shortToday&&e.shortYesterday===t.shortYesterday}handleLiveFault(e){for(let t of this.strategies.values())if(t.mode==="live"&&t.trading)this.failStrategy(t,"TD",Error(e))}applyTrade(e,t,r=!1,n=!0){let i=t.vtTradeId;if(!this.rememberTradeId(e.seenTrades,i))return;if(this.deps.recordTrade)try{this.deps.recordTrade({strategyId:e.id,name:e.name,mode:e.mode,vtSymbol:e.vtSymbol,trade:{...t},inventory:{...e.inventory},multiplier:this.deps.live?.getInstrument(e.instrumentID)?.volumeMultiple??null})}catch(u){this.writeLog(e.instance,`\u6210\u4EA4\u8BB0\u5F55\u5931\u8D25: ${u instanceof Error?u.message:String(u)}`)}if(this.deps.orderRisk.recordTrade(e.mode,t),this.applyInventory(e.inventory,t.direction,t.offset,t.volume),this.syncFrameworkState(e),e.expectedLivePos=J(e.inventory),e.mode==="live")e.expectedLiveInventory={...e.inventory};let o=(e.tradeVolumeByOrder.get(t.vtOrderId)??0)+t.volume;e.tradeVolumeByOrder.set(t.vtOrderId,o);let s=e.orders.get(t.vtOrderId);if(s)s.traded=Math.max(s.traded,Math.min(s.volume,o));let a={...t},d=s?{...s}:null,c=()=>{if(this.callStrategy(e,"onTrade",()=>(this.observe(e,{type:"trade",value:{...t}}),e.instance.onTrade({...t}))),s)this.pruneTerminalOrder(e,s);if(this.scheduleState(e,!0),e.mode==="paper"&&n)this.dispatchTrades("paper",a,d,"strategy")};if(r)this.scheduleState(e,!0),this.enqueue(c);else c()}applyInventory(e,t,r,n){if(r==="open"){if(t==="long")e.longToday+=n;else e.shortToday+=n;return}let i=t==="short"?"longToday":"shortToday",o=t==="short"?"longYesterday":"shortYesterday";if(r==="closeToday"){e[i]=Math.max(0,e[i]-n);return}if(r==="closeYesterday"){e[o]=Math.max(0,e[o]-n);return}let s=Math.min(e[o],n);e[o]-=s,e[i]=Math.max(0,e[i]-(n-s))}queueOrder(e,t){let r={...t},n=e.tradingDay;this.enqueue(()=>this.emitOrder(e,t,r,n))}emitOrder(e,t,r={...t},n=e.tradingDay){if(this.deps.orderRisk.recordOrder(e.mode,r,n),e.inited)this.callStrategy(e,"onOrder",()=>(this.observe(e,{type:"order",value:{...r,type:"order"}}),e.instance.onOrder({...r,type:"order"})));if(!w(r))this.pruneTerminalOrder(e,t)}emitOrderError(e,t,r,n,i,o,s){let a={type:"error",stage:"submit",code:t,vtSymbol:e.vtSymbol,direction:r,offset:n,price:i,volume:o,message:s,datetime:this.eventTimeMs??this.deps.now()};this.enqueue(()=>this.callStrategy(e,"onOrder",()=>(this.observe(e,{type:"order",value:{...a}}),e.instance.onOrder(a))))}pruneTerminalOrder(e,t){if(e.orders.get(t.vtOrderId)!==t)return;if(w(t))return;if((e.tradeVolumeByOrder.get(t.vtOrderId)??0)<t.traded)return;if(e.mode==="paper")this.deps.paperExecution?.onOrderClosed?.(t),this.terminalPaperOrders.add(t.vtOrderId);e.orders.delete(t.vtOrderId),e.tradeVolumeByOrder.delete(t.vtOrderId),this.orderOwners.delete(t.vtOrderId)}rememberTradeId(e,t){if(e.has(t))return!1;if(e.add(t),e.size>Fo){let r=e.values().next().value;if(r!==void 0)e.delete(r)}return!0}dispatchTimer(e){this.enqueue(()=>{for(let t of this.strategies.values())this.dispatchEvent(t,Object.freeze({type:"timer",now:e}))})}dispatchTrades(e,t,r,n,i){let o=Object.freeze({type:"trades",now:this.eventTimeMs??this.deps.now(),trade:Object.freeze({...t}),order:r?Object.freeze({...r,origin:n}):null});for(let s of this.strategies.values()){if(s.mode!==e)continue;let a=this.tradeClaimContext;this.tradeClaimContext=i?{...i,running:s,trade:o.trade}:null;try{this.dispatchEvent(s,o)}finally{this.tradeClaimContext=a}}}dispatchEvent(e,t){if(!e.inited||e.fault)return;let r=e.eventHandlers[t.type];for(let n of[...r]){if(e.fault)break;if(!r.has(n))continue;this.invokeAtTime(t.now,()=>this.callStrategy(e,`${t.type} event`,()=>n(t)))}}clearEventHandlers(e){for(let t of Object.values(e.eventHandlers))t.clear()}invokeAtTime(e,t){let r=this.eventTimeMs;this.eventTimeMs=e;try{return t()}finally{this.eventTimeMs=r}}rollPaperDay(e,t){if(!t||t===e.tradingDay)return;if(e.tradingDay){for(let r of e.orders.values()){if(!w(r))continue;r.status="cancelled",r.statusMessage="paper trading day changed",this.queueOrder(e,r)}e.inventory.longYesterday+=e.inventory.longToday,e.inventory.longToday=0,e.inventory.shortYesterday+=e.inventory.shortToday,e.inventory.shortToday=0}e.tradingDay=t,this.scheduleState(e,!0)}rollLiveDay(e,t){if(!t||t===e.tradingDay)return;let r=this.inventoryOnTradingDay(e,t);e.inventory=r,e.expectedLiveInventory={...r},e.expectedLivePos=J(r),e.tradingDay=t,this.syncFrameworkState(e)}roundPrice(e,t){let r=this.getPriceTick(e.instance);return Number((Math.round(t/r)*r).toFixed(10))}paperFill(e,t,r,n){let i=(e.direction==="long"?t.askPrice1:t.bidPrice1)??e.price,o=this.deps.paperExecution?.fillOrder?.(e,t,r,n)??{referencePrice:i,price:i};if(!Number.isFinite(o.referencePrice)||o.referencePrice<=0||!Number.isFinite(o.price)||o.price<=0)throw Error(`Paper \u6210\u4EA4\u4EF7\u975E\u6CD5: ${o.referencePrice}/${o.price}`);return o}cancelAllDirect(e){for(let t of e.orders.values()){if(!w(t))continue;if(e.mode==="paper")this.cancelOrder(e.instance,t.vtOrderId);else try{this.deps.live?.cancelOrder(t.vtOrderId)}catch(r){console.error(`[cta] ${e.id} \u64A4\u5355\u5931\u8D25: ${r instanceof Error?r.message:String(r)}`)}}}retainedOrdersMessage(e){return`\u7B56\u7565\u5DF2\u505C\u6B62\uFF0C\u4ECD\u6709 ${e} \u7B14\u59D4\u6258\u672A\u64A4\u9500\uFF0C\u53EF\u80FD\u7EE7\u7EED\u6210\u4EA4\uFF0C\u8BF7\u624B\u52A8\u64A4\u5355\u3002`}scheduleState(e,t=!1){if(t){e.stateTimer?.(),e.stateTimer=null,this.trySaveState(e);return}if(e.stateTimer)return;e.stateTimer=this.deps.schedule(()=>{e.stateTimer=null,this.trySaveState(e)},qo)}saveState(e){let t=this.serializeVariables(e);this.deps.stateStore.write({strategyId:e.id,vtSymbol:e.vtSymbol,mode:e.mode,bundleHash:e.hash,pos:J(e.inventory),variables:t,inventory:e.inventory,tradingDay:e.tradingDay}),this.observe(e,{type:"state",operation:"write",value:{pos:J(e.inventory),inventory:{...e.inventory},variables:t,tradingDay:e.tradingDay}})}serializeVariables(e){return Un(e.runtime.getStateVariables(),`\u7B56\u7565 ${e.id} variables`)}trySaveState(e){try{this.saveState(e)}catch(t){if(console.error(`[cta] ${e.id} \u72B6\u6001\u4FDD\u5B58\u5931\u8D25: ${t instanceof Error?t.message:String(t)}`),e.trading)this.failStrategy(e,"state",t)}}callStrategy(e,t,r){if(e.fault)return;try{this.invokeStrategySync(e,t,r),this.scheduleState(e)}catch(n){this.failStrategy(e,t,n)}}failStrategy(e,t,r){let n=r instanceof Error?r.message:String(r);if(e.fault)return;e.fault=`${t}: ${n}`,this.observe(e,{type:"fault",callback:t,message:n}),e.trading=!1,e.inited=!1,this.clearEventHandlers(e),this.syncFrameworkState(e),this.cancelAllDirect(e),console.error(`[cta] ${e.id} ${t} \u5F02\u5E38\uFF0C\u7B56\u7565\u5DF2\u505C\u6B62: ${n}`),this.publishHook("strategy.faulted",{...this.strategyIdentity(e),callback:t,reason:n})}emitRiskRejection(e,t,r,n,i,o,s){let a=this.deps.orderRisk.tradingDay(e.mode)||e.tradingDay||null;this.publishHook("risk.order_rejected",{source:"strategy",riskCode:t,mode:e.mode,vtSymbol:e.vtSymbol,tradingDay:a,direction:r,offset:n,price:i,volume:o,reason:s,strategyId:e.id})}strategyIdentity(e){return{strategyId:e.id,mode:e.mode,vtSymbol:e.vtSymbol}}publishHook(e,t){try{this.deps.emitHook?.(e,t)}catch(r){console.error(`[hooks] \u4E8B\u4EF6\u6295\u9012\u5931\u8D25 event=${e}: ${r instanceof Error?r.message:String(r)}`)}}enqueue(e){let t=this.eventTimeMs;if(this.eventQueue.push(t===null?e:()=>this.invokeAtTime(t,e)),this.dispatching)return;this.dispatching=!0;try{while(this.eventQueue.length>0)this.eventQueue.shift()()}finally{this.dispatching=!1}}queuePending(e,t){for(let r of this.pending.values()){if(r.running.instrumentID!==t)continue;if(r.events.length>=qn){r.overflowed=!0;continue}r.events.push(e)}}drainPending(e){while(e.events.length>0){let t=e.events.splice(0);for(let r of t){if(r.kind==="bar"){if(e.replayedBars.has(zn(r.value)))continue;this.callStrategy(e.running,"onBar",()=>e.running.instance.onBar(r.value))}else this.callStrategy(e.running,"onTick",()=>e.running.instance.onTick(r.value));if(e.running.fault)return}}}assertLiveInstrumentOwner(e){if(e.mode!=="live")return;let t=[...this.strategies.values()].find((r)=>B(r.id,r.mode)!==B(e.id,e.mode)&&r.mode==="live"&&r.instrumentID===e.instrumentID);if(t)throw Error(`Live \u5408\u7EA6 ${e.instrumentID} \u5DF2\u7531\u7B56\u7565 ${t.id} \u5360\u7528`)}requireInitializing(e,t){let r=this.requireInstance(e);if(this.initializing!==r)throw Error(`${t} \u53EA\u80FD\u5728 onInit() \u4E2D\u8C03\u7528`);return r}requireInstance(e){let t=this.instanceMap.get(e);if(!t)throw Error("\u672A\u77E5\u7B56\u7565\u5B9E\u4F8B");return t}findRunning(e,t){return this.strategies.get(B(e,t))??null}requireRunning(e,t){let r=this.findRunning(e,t);if(!r)throw Error(`\u7B56\u7565\u5B9E\u4F8B\u4E0D\u5B58\u5728: ${e}@${t}`);return r}findPending(e,t){return this.pending.get(B(e,t))??null}requirePending(e,t){let r=this.findPending(e,t);if(!r)throw Error(`\u7B56\u7565 ${e}@${t} \u6CA1\u6709\u5F85\u63D0\u4EA4\u53D8\u66F4`);return r}async dispose(e,t=!0){if(e.stateTimer?.(),e.stateTimer=null,t&&e.inited)this.trySaveState(e);this.instanceMap.delete(e.instance),this.clearEventHandlers(e);for(let r of e.orders.keys())this.orderOwners.delete(r)}invokeSync(e,t){let r=t();if(r&&typeof r.then==="function")throw Promise.resolve(r).catch(()=>{return}),Error(`${e} \u4E0D\u5141\u8BB8\u8FD4\u56DE Promise`)}invokeStrategySync(e,t,r){this.syncFrameworkState(e),this.observe(e,{type:"callback",callback:t,stage:"begin"});try{this.invokeSync(t,r)}finally{this.syncFrameworkState(e),this.observe(e,{type:"callback",callback:t,stage:"end"})}}observe(e,t){this.deps.observe({...t,strategyId:e.id,now:this.eventTimeMs??this.deps.now()})}syncFrameworkState(e){e.runtime.setRuntimeState({inited:e.inited,trading:e.trading,pos:J(e.inventory)})}}var jn=20,Ko=1000,Q="vibek-test",Yo={maxOrderVolume:1000,maxPosition:1e4,maxActiveOpenOrders:1000},Gn={dailyLimits:{totalOrderLimit:1e5,totalCancelLimit:1e5,totalTradeLimit:1e5,instrumentOrderLimit:1e5,instrumentCancelLimit:1e5,instrumentTradeLimit:1e5},duplicateOrderLimit:1e5};class ie{definition;fixture;events=[];orderEvents=[];tradeEvents=[];logs=[];hooks=[];submissions=[];cancelRequests=[];broker;callbackCounts={onInit:0,onStart:0,onStop:0,onTick:0,onBar:0};dataDir;stateStore;clock;traceRecorder;faults=[];aggregator=new qe({timeframes:["1min"]});barHistory=[];warmupSupplied=!1;paperSessionSequence=0;mode;setting;initialState;brokerState;executionLimits;riskSettings;paperExecution;runtime;running;live;gatewayControl;eventCounter=0;nextEventTimeMs;initialized=!1;initialStateWritten=!1;disposed=!1;firstSdkOrderViolation;constructor(e,t,r={}){this.definition=e;this.fixture=t;if(this.mode=r.mode??"live",r.execution!==void 0&&r.execution!=="scripted"&&r.execution!=="ctp")throw Error("Unknown test execution model");if(r.execution==="ctp"&&this.mode!=="live")throw Error("CTP execution requires live mode");if(r.execution==="ctp"&&r.brokerState)throw Error("CTP execution uses gatewayState");if(r.brokerState&&this.mode!=="live")throw Error("Broker state requires live mode");if(r.paperExecution&&this.mode!=="paper")throw Error("Paper execution hooks require paper mode");if(r.execution!=="ctp"&&(r.gatewayState||r.gatewaySession))throw Error("Gateway settings require CTP execution");this.setting=r.setting===void 0?ce(t.setting,"setting"):ce(r.setting,"setting"),this.initialState=r.initialState,this.brokerState=r.brokerState===void 0?void 0:structuredClone(r.brokerState),this.executionLimits=Wo(r.executionLimits),this.riskSettings=Jo(r.riskLimits),this.paperExecution=r.paperExecution,this.clock=new Ht(Ke(t)),this.traceRecorder=new Lt(()=>this.clock.now);let{paperExecution:n,...i}=r;if(this.traceRecorder.record("context",{fixture:{vtSymbol:t.vtSymbol,instrument:{priceTick:t.priceTick,size:t.size,name:t.name,minOrderVolume:t.minOrderVolume,maxOrderVolume:t.maxOrderVolume,longMarginRatio:t.longMarginRatio,shortMarginRatio:t.shortMarginRatio,isTrading:t.isTrading},...t.commission?{commission:t.commission}:{},setting:t.setting,seedPrice:t.seedPrice,tradingDay:t.tradingDay},options:i,...n?{customPaperExecution:!0}:{}}),r.execution==="ctp")this.live=new xe(t,this.clock,this.traceRecorder,r,{submissions:this.submissions,cancelRequests:this.cancelRequests});this.nextEventTimeMs=this.clock.now;let o={holdReports:()=>this.requireLive().holdReports(),resumeReports:()=>this.requireLive().resumeReports(),pendingReports:()=>this.requireLive().pendingReports(),deliverReport:(s)=>this.requireLive().deliverReport(s),repeatReport:(s)=>this.requireLive().repeatReport(s),snapshot:()=>this.requireLive().snapshot(),failNextSubmit:(s)=>this.requireLive().failNextSubmit(s),rejectSubmit:(s,a)=>this.requireLive().rejectSubmit(s,a),acknowledge:(s)=>this.requireLive().acknowledge(s),partialFill:(s,a,d)=>this.requireLive().partialFill(s,a,d),fill:(s,a)=>this.requireLive().fill(s,a),reject:(s,a)=>this.requireLive().reject(s,a),cancel:(s,a)=>this.requireLive().cancel(s,a),failNextCancel:(s)=>this.requireLive().failNextCancel(s),rejectCancel:(s,a)=>this.requireLive().rejectCancel(s,a),emitExternalOrder:(s)=>this.requireLive().emitExternalOrder(s),emitOrder:(s)=>this.requireLive().emitOrder(s),emitTrade:(s)=>this.requireLive().emitTrade(s),disconnect:()=>this.requireLive().disconnect(),reconcile:(s)=>this.requireLive().reconcile(s),fault:(s)=>this.requireLive().fault(s)};this.broker=this.observeCommands(o,"broker",["snapshot","pendingReports"]),this.dataDir=zo(Go(jo(),"vibek-strategy-test-runtime-")),this.stateStore=new $e(this.dataDir)}initialize(e={}){return this.traceRecorder.input({type:"initialize",...e},()=>this.initializeRuntime(e))}async initializeRuntime(e){if(this.disposed)throw Error("\u6D4B\u8BD5 Runtime \u5DF2\u91CA\u653E");if(this.initialized)throw Error("\u6D4B\u8BD5 Runtime \u5DF2\u521D\u59CB\u5316");if(e.warmupBars){let t=e.warmupBars.map((r,n)=>H(this.fixture,r,n));Ie(t,this.clock.now,this.fixture.instrumentID),this.barHistory.push(...t),this.warmupSupplied=!0}this.seedInitialState(),await this.createRuntime(),await this.runtime.warmup(),this.runtime.setTimerClock(this.clock.now),this.initialized=!0}async start(){this.requireInitialized(),await this.traceRecorder.input({type:"start"},()=>this.runtime.start(Q,this.mode))}async stop(){this.requireInitialized(),await this.traceRecorder.input({type:"stop"},()=>this.runtime.stop(Q,{},this.mode))}cancelOrder(e){this.requireInitialized(),this.traceRecorder.input({type:"cancelOrder",vtOrderId:e},()=>{this.runtime.cancelStrategyOrder(Q,e,this.mode)})}async restart(){this.requireInitialized(),await this.traceRecorder.input({type:"restart"},async()=>{await this.runtime.stop(Q,{},this.mode),await this.rebuildRuntime()})}async crashAndRestart(){this.requireInitialized(),await this.traceRecorder.input({type:"crashAndRestart"},()=>this.rebuildRuntime(!1))}setTime(e){if(this.disposed)throw Error("\u6D4B\u8BD5 Runtime \u5DF2\u91CA\u653E");let t=T(e,"\u6D4B\u8BD5\u65F6\u95F4");this.traceRecorder.input({type:"setTime",datetime:t},()=>{if(this.initialized)this.advanceClock(t);else this.clock.now=t}),this.nextEventTimeMs=t}advanceTime(e){if(this.disposed)throw Error("\u6D4B\u8BD5 Runtime \u5DF2\u91CA\u653E");let t=T(e,"\u63A8\u8FDB\u65F6\u95F4"),r=this.clock.now+t;if(!Number.isSafeInteger(r))throw Error("\u63A8\u8FDB\u540E\u7684\u6D4B\u8BD5\u65F6\u95F4\u8D85\u8FC7\u5B89\u5168\u6574\u6570\u8303\u56F4");this.traceRecorder.input({type:"advanceTime",milliseconds:e},()=>this.advanceClock(r)),this.nextEventTimeMs=r}pushBar(e,t={}){this.requireInitialized();let r=t.datetime??(e.barTime===void 0?Math.max(this.nextEventTimeMs,((this.barHistory.at(-1)?.barTime??-120)+120)*1000):(e.barTime+60)*1000),n=H(this.fixture,e,this.eventCounter,Math.floor(r/60000)*60-60);this.validateClosedBars([n],r),this.traceRecorder.input({type:"bar",value:n,datetime:r},()=>{this.recordEventTime(r),this.eventCounter++,this.aggregator.completeThrough(r),this.dispatchBars(this.mergeClosedBars(this.takeCompletedBars(),[n]))})}pushTick(e){this.pushMarketEvent(e,[])}pushMarketEvent(e,t){this.requireInitialized();let r=De(this.fixture,e,this.eventCounter,this.nextEventTimeMs);if(r.code!==this.fixture.instrumentID)throw Error("\u6D4B\u8BD5 Tick \u5408\u7EA6\u4E0E fixture \u4E0D\u5339\u914D");let n=t.map((o,s)=>H(this.fixture,o,s)),i=r.receivedAt??r.datetime;if(r.datetime>i||i-r.datetime>dt)throw Error("\u6D4B\u8BD5 Tick \u4EA4\u4ED8\u65F6\u95F4\u5FC5\u987B\u4F4D\u4E8E\u884C\u60C5\u65F6\u95F4\u4E4B\u540E\u7684 30 \u79D2\u4EE5\u5185");this.validateClosedBars(n,i),this.traceRecorder.input({type:"market",tick:r,closedBars:n},()=>{this.recordEventTime(i),this.eventCounter++,this.aggregator.pushTick(r);let o=this.mergeClosedBars(this.takeCompletedBars(),n);this.rememberBars(o);for(let s of o)this.traceRecorder.record("bar",s);this.runtime.handleMarketEvent(r,o)})}activeOrders(){if(this.requireInitialized(),!this.running)throw Error("\u6D4B\u8BD5 Runtime \u7684\u7B56\u7565\u5B9E\u4F8B\u4E0D\u5B58\u5728");return[...this.running.orders.values()].filter(w).map((e)=>({...e}))}snapshot(){this.requireInitialized();let e=this.runtime.snapshot().find((t)=>t.id===Q);if(!e||!this.running)throw Error("\u6D4B\u8BD5 Runtime \u7684\u7B56\u7565\u5B9E\u4F8B\u4E0D\u5B58\u5728");return{inited:e.inited,trading:e.trading,pos:e.pos,activeOrders:e.activeOrders,fault:e.fault,variables:ce(this.running.runtime.getStateVariables(),"variables"),inventory:{...this.running.inventory},now:this.clock.now}}get trace(){return this.traceRecorder.events}get gateway(){if(this.disposed)throw Error("\u6D4B\u8BD5 Runtime \u5DF2\u91CA\u653E");if(!(this.live instanceof xe))throw Error('Gateway controls require execution="ctp"');return this.gatewayControl??=this.observeCommands(this.live.gateway,"gateway",["pendingRequests"])}expectFault(e){let t=this.faults.find((r)=>!r.verified&&r.message===e);if(!t)throw Error(`\u672A\u53D1\u751F\u5F85\u9A8C\u8BC1\u7684 fault: ${e}`);t.verified=!0,this.traceRecorder.record("input",{type:"expectFault",message:e})}settleActiveOrders(){if(this.mode==="live"){if(!(this.live instanceof Oe))throw Error("CTP orders require explicit gateway reports");this.live.settleActiveOrders()}else for(let e of this.activeOrders())this.cancelOrder(e.vtOrderId)}assertHealthy(e){let t=this.snapshot();if(t.fault)throw Error(`${e}\u540E\u7B56\u7565 fault: ${t.fault}`);if(this.firstSdkOrderViolation)throw Error(`${e}\u89E6\u53D1 SDK \u975E\u6CD5\u4E0B\u5355: ${this.firstSdkOrderViolation}`)}async dispose(){if(!this.disposed){this.disposed=!0;try{await this.runtime?.close()}finally{if(this.live instanceof xe)this.live.close();this.traceRecorder.close(),Uo(this.dataDir,{recursive:!0,force:!0})}}let e=this.faults.filter((t)=>!t.verified);if(e.length)throw Error(`\u672A\u9A8C\u8BC1\u7684\u7B56\u7565 fault: ${e.map((t)=>t.message).join("; ")}`)}async createRuntime(){let e=this.stateStore.read(Q,this.mode),t=e?.inventory??de(),r={...this.fixture,tradingDay:e?.tradingDay||this.fixture.tradingDay};this.live??=new Oe(r,t,{order:0,trade:0},()=>this.clock.now,{submissions:this.submissions,cancelRequests:this.cancelRequests,record:(i,o)=>this.traceRecorder.record(i,o)},this.brokerState);let n=new He({settings:this.riskSettings,stateStore:new dr(this.dataDir),schedule:(i,o)=>this.clock.schedule(this.traceRecorder.bind(i),o)});n.setTradingDay("paper",r.tradingDay),this.runtime=new mr({createWarmupProvider:()=>new Bt(r,this.barHistory,this.clock.now,!this.warmupSupplied),stateStore:this.stateStore,live:this.live,paperExecution:{...this.paperExecution,onOrderSubmitted:(i)=>{let o={vtOrderId:i.vtOrderId,direction:i.direction,offset:i.offset,price:i.price,volume:i.volume};this.submissions.push(o),this.traceRecorder.record("submission",o)},onCancelRequested:(i)=>{this.cancelRequests.push(i.vtOrderId),this.traceRecorder.record("cancel",{vtOrderId:i.vtOrderId})}},orderRisk:n,executionLimits:this.executionLimits,log:(i)=>this.recordLog(i),now:()=>this.clock.now,schedule:(i,o)=>this.clock.schedule(this.traceRecorder.bind(i),o),createPaperSessionId:()=>String(++this.paperSessionSequence),observe:(i)=>this.observe(i),emitHook:(i,o,s)=>{if(i!=="strategy.event")return;let a=structuredClone({...o,occurredAt:s??this.clock.now});this.hooks.push(a),this.events.push({type:"hook",value:a,now:a.occurredAt}),this.traceRecorder.record("hook",a)}}),await this.live.connect(),this.running=this.runtime.addRestored({sourcePath:"strategy.ts",hash:"a".repeat(64),artifact:"strategy-test",loadedAt:new Date(0).toISOString(),mode:this.mode,definition:this.definition,instance:{id:Q,vtSymbol:this.fixture.vtSymbol,setting:this.setting}})}observe(e){if(this.traceRecorder.record(e.type,e),e.type==="callback"&&e.stage==="begin"&&Object.hasOwn(this.callbackCounts,e.callback))this.callbackCounts[e.callback]++;else if(e.type==="order"){let t=Zo(e.value);if(t.type==="error"&&(t.code==="invalidRequest"||t.code==="insufficientPosition"))this.firstSdkOrderViolation??=`${t.code}: ${t.message}`;this.orderEvents.push(t),this.events.push({type:"order",value:t,now:e.now})}else if(e.type==="trade")this.tradeEvents.push({...e.value}),this.events.push({type:"trade",value:{...e.value},now:e.now});else if(e.type==="fault")this.faults.push({message:`${e.callback}: ${e.message}`,verified:!1})}recordLog(e){let t=Qo(this.logs,e);this.traceRecorder.record("log",{message:t})}async rebuildRuntime(e=!0){await this.runtime.close({persist:e}),this.runtime=void 0,this.running=void 0,this.aggregator.reset(),this.initialized=!1,await this.createRuntime(),await this.runtime.warmup(),this.runtime.setTimerClock(this.clock.now),this.initialized=!0}recordEventTime(e){let t=e+60000;if(!Number.isSafeInteger(t))throw Error("\u884C\u60C5\u65F6\u95F4\u8D85\u8FC7\u5B89\u5168\u6574\u6570\u8303\u56F4");if(e<this.clock.now)throw Error("\u884C\u60C5\u65F6\u95F4\u4E0D\u80FD\u56DE\u9000");this.advanceClock(e),this.nextEventTimeMs=t}advanceClock(e){this.clock.advanceTo(e,this.initialized?()=>{this.traceRecorder.record("timer",{now:this.clock.now}),this.runtime.handleTimer(this.clock.now),this.aggregator.completeThrough(this.clock.now-dt),this.dispatchBars(this.takeCompletedBars())}:void 0)}takeCompletedBars(){let e=[...this.aggregator.getCompletedBars()];return this.aggregator.clearCompletedBars(),e.filter((t)=>t.barTime>(this.barHistory.at(-1)?.barTime??-1))}validateClosedBars(e,t){if(Ie(e,t,this.fixture.instrumentID),e.some((n)=>n.barTime<=(this.barHistory.at(-1)?.barTime??-1)))throw Error("\u95ED\u5408 Bar \u65F6\u95F4\u5FC5\u987B\u665A\u4E8E\u5DF2\u56DE\u653E\u5386\u53F2");let r=this.aggregator.getCurrentBar("1min");if(r&&t>=(r.barTime+60)*1000+dt&&e.some((n)=>n.barTime===r.barTime))throw Error("\u663E\u5F0F Bar \u7684\u4EA4\u4ED8\u665A\u4E8E\u81EA\u52A8\u95ED\u5408\u671F\u9650\uFF0C\u4E0D\u80FD\u66FF\u6362\u5DF2\u5230\u671F\u7684 Bar")}mergeClosedBars(e,t){let r=new Map(e.map((n)=>[n.barTime,n]));for(let n of t)r.set(n.barTime,n);return[...r.values()].sort((n,i)=>n.barTime-i.barTime)}rememberBars(e){this.barHistory.push(...e.map((t)=>({...t})))}dispatchBars(e){this.rememberBars(e);for(let t of e)this.traceRecorder.record("bar",t),this.runtime.handleBar(t)}seedInitialState(){if(this.initialStateWritten||!this.initialState)return;let e=We(this.initialState.inventory),t=this.initialState.variables===void 0?{}:ce(this.initialState.variables,"initialState.variables");this.stateStore.write({strategyId:Q,vtSymbol:this.fixture.vtSymbol,mode:this.mode,bundleHash:"a".repeat(64),pos:Mr(e),variables:t,inventory:e,tradingDay:this.fixture.tradingDay}),this.initialStateWritten=!0}requireInitialized(){if(this.disposed)throw Error("\u6D4B\u8BD5 Runtime \u5DF2\u91CA\u653E");if(!this.initialized||!this.runtime)throw Error("\u6D4B\u8BD5 Runtime \u5C1A\u672A initialize()")}requireLive(){if(this.requireInitialized(),this.mode!=="live"||!(this.live instanceof Oe))throw Error('broker \u63A7\u5236\u53EA\u9002\u7528\u4E8E mode="live"\u3001execution="scripted" \u7684\u6D4B\u8BD5 Runtime');return this.live}observeCommands(e,t,r){return new Proxy(e,{get:(n,i)=>{let o=Reflect.get(n,i);if(typeof o!=="function"||!Object.hasOwn(n,i)||r.includes(String(i)))return o;return(...s)=>this.traceRecorder.input({type:t,method:i,args:s},()=>Reflect.apply(o,n,s))}})}}function Wo(e){let t={...Yo,...e};return{maxOrderVolume:x(t.maxOrderVolume,"executionLimits.maxOrderVolume"),maxPosition:x(t.maxPosition,"executionLimits.maxPosition"),maxActiveOpenOrders:x(t.maxActiveOpenOrders,"executionLimits.maxActiveOpenOrders")}}function Jo(e){let t={...Gn.dailyLimits,...e?.dailyLimits};for(let r of Object.keys(t))x(t[r],`riskLimits.dailyLimits.${r}`);return{dailyLimits:t,duplicateOrderLimit:x(e?.duplicateOrderLimit??Gn.duplicateOrderLimit,"riskLimits.duplicateOrderLimit")}}function Qo(e,t){let r=Xo(es(t),Ko);if(e.push(r),e.length>jn)e.splice(0,e.length-jn);return r}function Zo(e){return{...e}}function Xo(e,t){let r=Buffer.from(e);if(r.length<=t)return e;return`${r.subarray(0,t).toString("utf8")}...`}function es(e){return e.replace(/\bsk-[A-Za-z0-9_-]{6,}\b/g,"[redacted]").replace(/((?:api[_ -]?key|authorization|access[_ -]?token)\s*[:=]\s*)\S+/gi,"$1[redacted]")}async function pr(e,t,r){await e.initialize(),await e.start();for(let n of[0,1,-1,2,-2,0]){if(e.pushTick({lastPrice:Math.max(t.priceTick,t.seedPrice+n*t.priceTick),askVolume1:1,bidVolume1:1}),e.advanceTime(1500),r==="live")for(let i of e.activeOrders()){if(i.status==="submitting")e.broker.acknowledge(i.vtOrderId);if(!e.activeOrders().some((o)=>o.vtOrderId===i.vtOrderId))continue;if(i.volume-i.traded>1)e.broker.partialFill(i.vtOrderId,1);else e.broker.fill(i.vtOrderId)}e.advanceTime(60000),e.assertHealthy("\u786E\u5B9A\u6027\u56DE\u653E")}return await e.stop(),e.settleActiveOrders(),await e.restart(),await e.start(),e.pushTick({lastPrice:t.seedPrice}),e.advanceTime(1000),await e.stop(),e.settleActiveOrders(),e.assertHealthy("\u786E\u5B9A\u6027\u91CD\u542F"),{trace:e.trace,submissions:e.submissions,cancelRequests:e.cancelRequests,events:e.events,orderEvents:e.orderEvents,tradeEvents:e.tradeEvents,hooks:e.hooks,logs:e.logs,snapshot:e.snapshot()}}import{isDeepStrictEqual as Yn,inspect as Wn}from"util";class ft extends Error{step;scenario;trace;constructor(e,t,r,n){super(`Strategy scenario failed at step ${e}${t.seed===void 0?"":` (seed ${t.seed})`}: ${n instanceof Error?n.message:String(n)}
50
- Replay: ${Jn(t)}`,{cause:n});this.step=e;this.scenario=t;this.trace=r;this.name="StrategyScenarioError"}}async function gr(e,t,r={}){if(yt(t),t.context?.customPaperExecution&&!r.paperExecution)throw Error("Custom Paper hooks must be supplied to replay this scenario");let n=new ie(e.strategy,Y(t.context?.fixture??e.fixture),{...t.context?.options,...r}),i={...t,context:n.trace[0].value},o=0,s=new Map;try{for(;o<t.steps.length;o++){let d=t.steps[o];if(d.at!==void 0)n.setTime(d.at);if(d.action.type==="await"){let c=s.get(d.action.task);if(!c)throw Error(`Scenario task does not exist: ${d.action.task}`);let u=await c;if(s.delete(d.action.task),d.action.error===void 0){if("error"in u)throw u.error}else if(!("error"in u)||(u.error instanceof Error?u.error.message:String(u.error))!==d.action.error)throw Error(`Scenario task did not reject with: ${d.action.error}`)}else if(d.task)s.set(d.task,Kn(n,d.action).then(()=>({}),(c)=>({error:c})));else await Kn(n,d.action)}let a={...t.seed===void 0?{}:{seed:t.seed},trace:n.trace,snapshot:n.snapshot(),submissions:structuredClone(n.submissions),cancelRequests:[...n.cancelRequests]};return await n.dispose(),a}catch(a){try{await n.dispose()}catch(d){if(d!==a)a=AggregateError([a,d],String(a))}throw new ft(o,i,n.trace,a)}}async function ts(e,t,r={}){let n=await gr(e,t,r),i=await gr(e,t,r);try{if(fr(n.trace,i.trace),!Yn(n.snapshot,i.snapshot))throw Error(`Strategy replay snapshot differs:
69
+ `+`\u82E5\u8981\u653E\u5F03\u65E7\u72B6\u6001\uFF0C\u8BF7\u6267\u884C vibek strategy unload ${e.oldState.strategyId}@${e.oldState.mode} \u540E\u91CD\u65B0 load\uFF1B`+"unload \u4F1A\u6C38\u4E45\u5220\u9664\u8BE5\u6A21\u5F0F\u7684\u72B6\u6001\u3001\u6301\u4ED3\u548C\u53D8\u91CF\u3002\u82E5\u5F53\u524D\u6CA1\u6709\u5DF2\u52A0\u8F7D\u5B9E\u4F8B\uFF0C\u8BF7\u6309\u4E0A\u8FF0\u8DEF\u5F84\u624B\u52A8\u5220\u9664\u65E7 state \u6587\u4EF6\u3002");this.details=e;this.name="StrategyStateCompatibilityError"}}function or(e){return e!==null&&typeof e==="object"&&!Array.isArray(e)}function mt(e,t,r){if(!Number.isInteger(e)||e<0)throw Error(`${r}: ${t} \u975E\u6CD5`);return e}function Pn(e,t){if(!or(e))throw Error(`${t}: \u7B56\u7565\u72B6\u6001\u5FC5\u987B\u662F\u5BF9\u8C61`);if(Object.keys(e).some((i)=>!Ro.has(i)))throw Error(`${t}: \u7B56\u7565\u72B6\u6001\u5305\u542B\u672A\u77E5\u5B57\u6BB5`);if(typeof e.strategyId!=="string"||typeof e.vtSymbol!=="string"||e.mode!=="paper"&&e.mode!=="live")throw Error(`${t}: \u7B56\u7565\u72B6\u6001\u8EAB\u4EFD\u975E\u6CD5`);if(typeof e.bundleHash!=="string"||!/^[a-f0-9]{64}$/.test(e.bundleHash)||typeof e.savedAt!=="string"||!or(e.variables)||typeof e.tradingDay!=="string"||!or(e.inventory))throw Error(`${t}: \u7B56\u7565\u72B6\u6001\u5185\u5BB9\u975E\u6CD5`);let r={longToday:mt(e.inventory.longToday,"longToday",t),longYesterday:mt(e.inventory.longYesterday,"longYesterday",t),shortToday:mt(e.inventory.shortToday,"shortToday",t),shortYesterday:mt(e.inventory.shortYesterday,"shortYesterday",t)};if(!Number.isInteger(e.pos))throw Error(`${t}: pos \u975E\u6CD5`);if(r.longToday+r.longYesterday-r.shortToday-r.shortYesterday!==e.pos)throw Error(`${t}: pos \u4E0E inventory \u4E0D\u4E00\u81F4`);return{strategyId:e.strategyId,vtSymbol:e.vtSymbol,mode:e.mode,bundleHash:e.bundleHash,savedAt:e.savedAt,pos:e.pos,variables:e.variables,inventory:r,tradingDay:e.tradingDay}}class $e{root;constructor(e=pe.data){this.root=ir(e,"strategy-state")}read(e,t){let r=this.path(e,t);if(!ko(r))return null;return Pn(JSON.parse(Eo(r,"utf8")),r)}assertCompatible(e,t,r,n){let i=this.read(e,t);if(!i)return;if(i.strategyId!==e||i.mode!==t)throw Error(`${this.path(e,t)}: \u7B56\u7565 ${e} \u72B6\u6001\u8EAB\u4EFD\u4E0D\u5339\u914D`);if(i.vtSymbol!==r)throw Error(`${this.path(e,t)}: \u7B56\u7565 ${e} \u7684\u72B6\u6001\u5C5E\u4E8E ${i.vtSymbol}\uFF0C\u4E0D\u80FD\u6062\u590D\u5230 ${r}`);let o=Object.keys(i.variables).sort(),s=[...n].sort(),a=new Set(o),d=new Set(s),c=s.filter((l)=>!a.has(l)),u=o.filter((l)=>!d.has(l));if(c.length===0&&u.length===0)return;throw new $n({statePath:this.path(e,t),oldState:i,oldSchema:{variables:o},newSchema:{variables:s},addedVariables:c,removedVariables:u})}write(e){let t=this.path(e.strategyId,e.mode);To(ir(this.root,e.strategyId),{recursive:!0});let r={savedAt:new Date().toISOString(),...e};Pn(r,t);let n=`${JSON.stringify(r,null,2)}
70
+ `;if(Buffer.byteLength(n)>262144)throw Error(`\u7B56\u7565 ${e.strategyId} variables \u8D85\u8FC7 256KB`);let i=`${t}.${process.pid}-${Oo()}.tmp`;try{Do(i,n,{encoding:"utf8",mode:384,flag:"wx"}),Io(i,t)}finally{try{Cn(i)}catch{}}}remove(e,t){let r=this.path(e,t);try{return Cn(r),!0}catch(n){if(n.code==="ENOENT")return!1;throw n}}path(e,t){if(!we.test(e))throw Error(`\u7B56\u7565 ID \u975E\u6CD5: ${e}`);if(t!=="paper"&&t!=="live")throw Error(`\u7B56\u7565 mode \u975E\u6CD5: ${t}`);return ir(this.root,e,`${t}.json`)}}import{randomUUID as _o}from"crypto";import{existsSync as xo,mkdirSync as Co,readFileSync as Po,renameSync as $o,unlinkSync as Mo,writeFileSync as Ao}from"fs";import{dirname as Bo,join as Ho}from"path";var pt=(e,t)=>{let r=setTimeout(e,t);return()=>clearTimeout(r)};var Mn=4194304,gt=/^\d{8}$/;function ar(){return{orders:0,cancels:0,trades:0}}function Me(e=""){return{tradingDay:e,total:ar(),instruments:new Map,duplicateAttempts:new Map,duplicateRejected:0,orderIds:new Set,cancelledOrderIds:new Set,tradeIds:new Set}}function Ae(e){return e!==null&&typeof e==="object"&&!Array.isArray(e)}function Be(e,t){if(!Number.isSafeInteger(e)||e<0)throw Error(`${t} \u5FC5\u987B\u662F\u975E\u8D1F\u6574\u6570`);return e}function An(e,t){if(!Ae(e))throw Error(`${t} \u5FC5\u987B\u662F JSON \u5BF9\u8C61`);return{orders:Be(e.orders,`${t}.orders`),cancels:Be(e.cancels,`${t}.cancels`),trades:Be(e.trades,`${t}.trades`)}}function Bn(e,t){if(!Ae(e))throw Error(`${t} \u5FC5\u987B\u662F JSON \u5BF9\u8C61`);let r=typeof e.tradingDay==="string"?e.tradingDay:"";if(r&&!gt.test(r))throw Error(`${t}.tradingDay \u975E\u6CD5`);if(!Ae(e.instruments))throw Error(`${t}.instruments \u5FC5\u987B\u662F JSON \u5BF9\u8C61`);let n={};for(let[o,s]of Object.entries(e.instruments)){if(!o||o.length>128)throw Error(`${t}.instruments key \u975E\u6CD5`);n[o]=An(s,`${t}.instruments.${o}`)}if(!Ae(e.duplicateAttempts))throw Error(`${t}.duplicateAttempts \u5FC5\u987B\u662F JSON \u5BF9\u8C61`);let i={};for(let[o,s]of Object.entries(e.duplicateAttempts))i[o]=Be(s,`${t}.duplicateAttempts`);return{tradingDay:r,total:An(e.total,`${t}.total`),instruments:n,duplicateAttempts:i,duplicateRejected:Be(e.duplicateRejected,`${t}.duplicateRejected`)}}function Hn(e,t){if(!Ae(e)||Object.keys(e).some((r)=>!["savedAt","paper","live"].includes(r))||typeof e.savedAt!=="string")throw Error(`${t}: \u98CE\u63A7\u72B6\u6001\u7ED3\u6784\u975E\u6CD5`);return{savedAt:e.savedAt,paper:Bn(e.paper,`${t}.paper`),live:Bn(e.live,`${t}.live`)}}function Ln(e){return{tradingDay:e.tradingDay,total:{...e.total},instruments:new Map(Object.entries(e.instruments).map(([t,r])=>[t,{...r}])),duplicateAttempts:new Map(Object.entries(e.duplicateAttempts)),duplicateRejected:e.duplicateRejected,orderIds:new Set,cancelledOrderIds:new Set,tradeIds:new Set}}function Nn(e){return{tradingDay:e.tradingDay,total:{...e.total},instruments:Object.fromEntries([...e.instruments.entries()].sort(([t],[r])=>t.localeCompare(r)).map(([t,r])=>[t,{...r}])),duplicateAttempts:Object.fromEntries([...e.duplicateAttempts.entries()].sort(([t],[r])=>t.localeCompare(r))),duplicateRejected:e.duplicateRejected}}function Lo(){return{dailyLimits:{...re.trading.dailyLimits},duplicateOrderLimit:re.trading.duplicateOrders.duplicateOrderLimit}}function Fn(e){return JSON.stringify([e.vtSymbol.toUpperCase(),e.direction,e.offset,e.price,e.volume])}function sr(e,t){e.orders=Math.max(e.orders,t.orders),e.cancels=Math.max(e.cancels,t.cancels),e.trades=Math.max(e.trades,t.trades)}function No(e){let t=ar();for(let r of e)t.orders+=r.orders,t.cancels+=r.cancels,t.trades+=r.trades;return t}class dr{path;constructor(e=pe.data){this.path=Ho(e,"risk-state.json")}read(){if(!xo(this.path))return null;let e=Po(this.path,"utf8");if(Buffer.byteLength(e)>Mn)throw Error(`${this.path}: \u98CE\u63A7\u72B6\u6001\u8D85\u8FC7 4MB`);try{return Hn(JSON.parse(e),this.path)}catch(t){throw Error(`${this.path}: \u98CE\u63A7\u72B6\u6001\u65E0\u6548: ${t instanceof Error?t.message:String(t)}`)}}write(e){let t={savedAt:new Date().toISOString(),...e};Hn(t,this.path);let r=`${JSON.stringify(t,null,2)}
71
+ `;if(Buffer.byteLength(r)>Mn)throw Error(`${this.path}: \u98CE\u63A7\u72B6\u6001\u8D85\u8FC7 4MB`);Co(Bo(this.path),{recursive:!0});let n=`${this.path}.${process.pid}-${_o()}.tmp`;try{Ao(n,r,{encoding:"utf8",mode:384,flag:"wx"}),$o(n,this.path)}finally{try{Mo(n)}catch{}}}}class He{settings;paper=Me();live=Me();stateStore;persistDelayMs;schedule;persistTimer=null;dirty=!1;constructor(e={}){this.settings=e.settings??Lo(),this.stateStore=e.stateStore??null,this.persistDelayMs=e.persistDelayMs??250,this.schedule=e.schedule??pt;let t=this.stateStore?.read();if(t)this.paper=Ln(t.paper),this.live=Ln(t.live)}setTradingDay(e,t){if(!gt.test(t))return;let r=this.mode(e);if(r.tradingDay===t)return;if(r.tradingDay&&t<r.tradingDay)return;this.replaceMode(e,Me(t)),this.markDirty()}checkOpen(e){return this.checkOpenDetailed(e)?.message??null}checkOpenDetailed(e,t={}){if(e.offset!=="open")return null;let r=t.recordAttempt!==!1,n;if(r)this.setTradingDay(e.mode,e.tradingDay),n=this.mode(e.mode);else{let a=this.mode(e.mode);n=gt.test(e.tradingDay)&&(!a.tradingDay||e.tradingDay>a.tradingDay)?Me(e.tradingDay):a}if(!n.tradingDay)return{code:"trading_day_unresolved",message:"\u98CE\u63A7 TradingDay \u5C1A\u672A\u786E\u5B9A"};if(n.tradingDay!==e.tradingDay)return{code:"trading_day_mismatch",message:`\u98CE\u63A7 TradingDay \u4E0D\u4E00\u81F4 ${n.tradingDay}/${e.tradingDay||"(\u7A7A)"}`};let i=this.dailyFailure(n,e.vtSymbol.toUpperCase());if(i)return i;let o=Fn(e),s=(n.duplicateAttempts.get(o)??0)+1;if(s>=this.settings.duplicateOrderLimit){if(r)n.duplicateAttempts.set(o,s),n.duplicateRejected++,this.markDirty();return{code:"duplicate_order_limit",message:`\u76F8\u540C\u5F00\u4ED3\u8BF7\u6C42\u5F53\u65E5\u7B2C ${s} \u6B21\uFF0C\u8FBE\u5230\u91CD\u590D\u62A5\u5355\u9608\u503C ${this.settings.duplicateOrderLimit}`}}if(r)n.duplicateAttempts.set(o,s),this.markDirty();return null}recordOrder(e,t,r=""){if(r)this.setTradingDay(e,r);let n=this.mode(e);if(!n.tradingDay||r&&n.tradingDay!==r)return;let i=t.vtSymbol.toUpperCase(),o=!1;if(!n.orderIds.has(t.vtOrderId))n.orderIds.add(t.vtOrderId),this.increment(n,i,"orders"),o=!0;if(t.status==="cancelled"&&!n.cancelledOrderIds.has(t.vtOrderId))n.cancelledOrderIds.add(t.vtOrderId),this.increment(n,i,"cancels"),o=!0;if(o)this.markDirty()}recordTrade(e,t){this.setTradingDay(e,t.tradingDay);let r=this.mode(e);if(!r.tradingDay||r.tradingDay!==t.tradingDay||r.tradeIds.has(t.vtTradeId))return;r.tradeIds.add(t.vtTradeId),this.increment(r,t.vtSymbol.toUpperCase(),"trades"),this.markDirty()}reconcileLive(e){if(!gt.test(e.tradingDay))throw Error(`Live \u98CE\u63A7 TradingDay \u975E\u6CD5: ${e.tradingDay}`);if(this.setTradingDay("live",e.tradingDay),this.live.tradingDay!==e.tradingDay)throw Error(`Live \u98CE\u63A7 TradingDay \u56DE\u9000: ${this.live.tradingDay}/${e.tradingDay}`);let t=this.live,r=Me(e.tradingDay);for(let n of e.orders)this.addSnapshotOrder(r,n);for(let n of e.trades)this.addSnapshotTrade(r,n);t.orderIds=new Set([...t.orderIds,...r.orderIds]),t.cancelledOrderIds=new Set([...t.cancelledOrderIds,...r.cancelledOrderIds]),t.tradeIds=new Set([...t.tradeIds,...r.tradeIds]),sr(t.total,r.total);for(let[n,i]of r.instruments){let o=this.instrumentCounts(t,n);sr(o,i)}sr(t.total,No(t.instruments.values()));for(let[n,i]of r.duplicateAttempts)t.duplicateAttempts.set(n,Math.max(t.duplicateAttempts.get(n)??0,i));this.markDirty()}snapshot(){return{limits:{dailyLimits:{...this.settings.dailyLimits},duplicateOrderLimit:this.settings.duplicateOrderLimit},paper:this.modeSnapshot(this.paper),live:this.modeSnapshot(this.live)}}tradingDay(e){return this.mode(e).tradingDay}flush(){if(this.persistTimer?.(),this.persistTimer=null,!this.dirty||!this.stateStore)return;this.stateStore.write({paper:Nn(this.paper),live:Nn(this.live)}),this.dirty=!1}close({persist:e=!0}={}){if(e)this.flush();else this.persistTimer?.(),this.persistTimer=null}dailyFailure(e,t){let r=this.settings.dailyLimits,n=this.instrumentCounts(e,t),o=[[e.total.orders,r.totalOrderLimit,"\u5F53\u65E5\u5168\u5C40\u59D4\u6258","daily_total_order_limit"],[e.total.cancels,r.totalCancelLimit,"\u5F53\u65E5\u5168\u5C40\u64A4\u5355","daily_total_cancel_limit"],[e.total.trades,r.totalTradeLimit,"\u5F53\u65E5\u5168\u5C40\u6210\u4EA4","daily_total_trade_limit"],[n.orders,r.instrumentOrderLimit,`${t} \u5F53\u65E5\u59D4\u6258`,"daily_instrument_order_limit"],[n.cancels,r.instrumentCancelLimit,`${t} \u5F53\u65E5\u64A4\u5355`,"daily_instrument_cancel_limit"],[n.trades,r.instrumentTradeLimit,`${t} \u5F53\u65E5\u6210\u4EA4`,"daily_instrument_trade_limit"]].find(([s,a])=>s>=a);return o?{code:o[3],message:`${o[2]}\u8FBE\u5230\u4E0A\u9650 ${o[0]}/${o[1]}`}:null}addSnapshotOrder(e,t){if(t.identity.tradingDay!==e.tradingDay||e.orderIds.has(t.vtOrderId))return;if(e.orderIds.add(t.vtOrderId),this.increment(e,t.vtSymbol.toUpperCase(),"orders"),t.status==="cancelled")e.cancelledOrderIds.add(t.vtOrderId),this.increment(e,t.vtSymbol.toUpperCase(),"cancels");if(t.offset==="open"){let r=Fn({vtSymbol:t.vtSymbol,direction:t.direction,offset:t.offset,price:t.price,volume:t.volume});e.duplicateAttempts.set(r,(e.duplicateAttempts.get(r)??0)+1)}}addSnapshotTrade(e,t){if(t.tradingDay!==e.tradingDay||e.tradeIds.has(t.vtTradeId))return;e.tradeIds.add(t.vtTradeId),this.increment(e,t.vtSymbol.toUpperCase(),"trades")}increment(e,t,r){e.total[r]++,this.instrumentCounts(e,t)[r]++}instrumentCounts(e,t){let r=e.instruments.get(t);if(!r)r=ar(),e.instruments.set(t,r);return r}mode(e){return e==="paper"?this.paper:this.live}replaceMode(e,t){if(e==="paper")this.paper=t;else this.live=t}modeSnapshot(e){let t=0,r=0;for(let n of e.duplicateAttempts.values()){if(n>=2)t++;r=Math.max(r,n)}return{tradingDay:e.tradingDay,total:{...e.total},instruments:Object.fromEntries([...e.instruments.entries()].sort(([n],[i])=>n.localeCompare(i)).map(([n,i])=>[n,{...i}])),duplicateRequests:{trackedKeys:e.duplicateAttempts.size,repeatedKeys:t,maxAttempts:r,rejected:e.duplicateRejected}}}markDirty(){if(this.dirty=!0,!this.stateStore||this.persistTimer)return;this.persistTimer=this.schedule(()=>{this.persistTimer=null,this.flush()},this.persistDelayMs)}}var Vn=1e5,Vo=1e5,qo=500;function cr(){return{longToday:0,longYesterday:0,shortToday:0,shortYesterday:0}}function B(e,t){return`${t}:${e}`}function qn(e){return e!==null&&typeof e==="object"&&!Array.isArray(e)}function lr(e,t,r){if(e===null||typeof e==="string"||typeof e==="boolean")return;if(typeof e==="number"){if(!Number.isFinite(e))throw Error(`${t} \u5305\u542B\u975E\u6709\u9650\u6570\u5B57`);return}if(typeof e!=="object")throw Error(`${t} \u5305\u542B\u4E0D\u53EF\u5E8F\u5217\u5316\u7684 ${typeof e}`);if(r.has(e))throw Error(`${t} \u5305\u542B\u5FAA\u73AF\u5F15\u7528`);if(r.add(e),Array.isArray(e))for(let n=0;n<e.length;n++)lr(e[n],`${t}[${n}]`,r);else{let n=Object.getPrototypeOf(e);if(n!==Object.prototype&&n!==null)throw Error(`${t} \u5FC5\u987B\u662F\u666E\u901A\u5BF9\u8C61\u6216\u6570\u7EC4`);for(let[i,o]of Object.entries(e))lr(o,`${t}.${i}`,r)}r.delete(e)}function Un(e,t){return lr(e,t,new Set),JSON.parse(JSON.stringify(e))}function zn(e){return`${e.code}\x00${e.timeframe}\x00${e.barTime}`}function J(e){return e.longToday+e.longYesterday-e.shortToday-e.shortYesterday}function ur(e){if(!qn(e))throw Error("\u7F3A\u5C11\u7B56\u7565\u5B9E\u4F8B\u914D\u7F6E");let{id:t,vtSymbol:r,setting:n}=e,i=Object.keys(e).find((o)=>o!=="id"&&o!=="vtSymbol"&&o!=="setting");if(i)throw Error(`\u7B56\u7565\u5B9E\u4F8B\u914D\u7F6E\u4E0D\u652F\u6301\u5B57\u6BB5 "${i}"`);if(typeof t!=="string"||!we.test(t))throw Error("\u7B56\u7565 id \u5FC5\u987B\u4E3A 1-64 \u4F4D\u5B57\u6BCD\u3001\u6570\u5B57\u3001\u70B9\u3001\u4E0B\u5212\u7EBF\u6216\u8FDE\u5B57\u7B26\uFF0C\u5E76\u4EE5\u5B57\u6BCD\u6216\u6570\u5B57\u5F00\u5934");if(typeof r!=="string")throw Error(`\u7B56\u7565 ${t} \u7F3A\u5C11 vtSymbol`);if(!qn(n))throw Error(`\u7B56\u7565 ${t} \u7684 setting \u5FC5\u987B\u662F\u5BF9\u8C61`);return{id:t,vtSymbol:K(r).vtSymbol,setting:Un(n,`\u7B56\u7565 ${t} setting`)}}function zo(){let e=nr(!0);return{getBars:async(t,r)=>{let n=_r(r.timeframe,r.count),i=await e.getLatestBars(t,"1min",n),o=ke(i,r.timeframe,r.count);if(o.selectedCount<r.count)throw Error(`\u5408\u7EA6 ${t} \u9884\u70ED\u6570\u636E\u4E0D\u8DB3\uFF1A\u9700\u8981 ${r.count} \u6839\u95ED\u5408 ${r.timeframe} Bar\uFF0C\u4EC5\u6709 ${o.availableCount} \u6839`);return o.bars},destroy:()=>e.destroy()}}class mr{strategies=new Map;instanceMap=new Map;orderOwners=new Map;terminalPaperOrders=new Set;liveOrders=new Map;liveTradeIds=new Set;pending=new Map;deps;cleanups=[];eventQueue=[];dispatching=!1;initializing=null;liveTradingDay="";timerCursorMs=null;eventTimeMs=null;tradeClaimContext=null;constructor(e={}){if(this.deps={createWarmupProvider:zo,stateStore:new $e,live:null,paperExecution:null,recordTrade:null,orderRisk:new He,executionLimits:{maxOrderVolume:re.trading.maxOrderVolume,maxPosition:re.trading.maxPosition,maxActiveOpenOrders:re.trading.maxActiveOpenOrders},log:(t)=>console.log(t),now:Date.now,schedule:pt,createPaperSessionId:Fo,observe:()=>{},emitHook:null,...e},this.deps.live)this.cleanups.push(this.deps.live.onOrder((t)=>this.enqueue(()=>{this.deps.orderRisk.recordOrder("live",t,t.identity.tradingDay),this.handleLiveOrder(t)})),this.deps.live.onTrade((t)=>this.enqueue(()=>{this.deps.orderRisk.recordTrade("live",t),this.handleLiveTrade(t)})),this.deps.live.onOrderError((t)=>this.enqueue(()=>this.handleLiveError(t))),this.deps.live.onReconciled((t)=>this.handleLiveReconciled(t)),this.deps.live.onFault((t)=>this.enqueue(()=>this.handleLiveFault(t))))}prepare(e){if(e.mode!=="paper"&&e.mode!=="live")throw Error("\u7B56\u7565 mode \u5FC5\u987B\u662F paper \u6216 live");let t=ur(e.instance),r=K(t.vtSymbol),n=Se(e.definition,t.id,t.setting),i={id:t.id,name:n.ctor.name||t.id,ctor:n.ctor,instance:n.instance,runtime:n.runtime,vtSymbol:r.vtSymbol,instrumentID:r.instrumentID,setting:n.effectiveSetting,enabled:e.enabled??e.mode==="paper",mode:e.mode,sourcePath:e.sourcePath,hash:e.hash,artifact:e.artifact,loadedAt:e.loadedAt,inventory:cr(),orders:new Map,inited:!1,trading:!1,fault:null,expectedLivePos:null,expectedLiveInventory:null,tradingDay:"",stateTimer:null,warmupRequests:[],paperSessionId:this.deps.createPaperSessionId(),paperOrderCounter:0,paperTradeCounter:0,seenTrades:new Set,tradeVolumeByOrder:new Map,eventHandlers:{timer:new Set,trades:new Set}};return n.runtime.bindContext({ctaEngine:this,strategyName:t.id,vtSymbol:r.vtSymbol,mode:e.mode,setting:n.effectiveSetting}),this.assertLiveInstrumentOwner(i),this.instanceMap.set(n.instance,i),i}addRestored(e){let t=ur(e.instance),r=B(t.id,e.mode);if(this.strategies.has(r))throw Error(`\u7B56\u7565\u5B9E\u4F8B\u91CD\u590D: ${t.id} (${e.mode})`);let n=this.prepare(e);return this.strategies.set(r,n),n}assertStateCompatible(e){this.deps.stateStore.assertCompatible(e.id,e.mode,e.vtSymbol,e.ctor.variables??[])}async warmup(){for(let e of this.strategies.values())if(!e.inited)await this.warmupOne(e)}canInitialize(){return this.deps.live?.phase==="running"}async prepareMetadata(){for(let e of this.strategies.values())await this.prepareContractMetadata(e)}async preparePendingMetadata(e,t){await this.prepareContractMetadata(this.requirePending(e,t).running)}beginReplace(e){let t=ur(e.instance),r=B(t.id,e.mode),n=this.strategies.get(r);if(n?.trading)throw Error(`\u7B56\u7565 ${n.id} \u8FD0\u884C\u4E2D\uFF0C\u8BF7\u5148\u505C\u6B62\u518D\u66F4\u65B0`);if(n)this.assertOrdersSettled(n.id,n.mode);if(n&&n.vtSymbol!==t.vtSymbol)throw Error(`\u7B56\u7565 ${n.id} \u5DF2\u7ED1\u5B9A ${n.vtSymbol}\uFF0C\u66F4\u6362\u5408\u7EA6\u5FC5\u987B\u4F7F\u7528\u65B0\u7684\u5B9E\u4F8B ID`);let i=this.prepare(e);if(this.pending.has(r))throw this.instanceMap.delete(i.instance),Error(`\u7B56\u7565 ${i.id} (${i.mode}) \u5DF2\u5728\u52A0\u8F7D\u4E2D`);return this.pending.set(r,{running:i,events:[],replayedBars:new Set,overflowed:!1,warmed:!1}),i}async warmupPending(e,t,{restoreState:r=!0}={}){let n=this.requirePending(e,t);if(await this.warmupOne(n.running,n.replayedBars,!1,r),n.warmed=!0,n.overflowed)throw Error(`\u7B56\u7565 ${e} \u521D\u59CB\u5316\u671F\u95F4\u7F13\u5B58\u884C\u60C5\u8D85\u8FC7 ${Vn} \u6761`)}async commitPending(e,t){let r=this.requirePending(e,t),n=B(e,r.running.mode);if(!r.warmed)throw Error(`\u7B56\u7565 ${e} \u5C1A\u672A\u5B8C\u6210\u521D\u59CB\u5316`);if(r.overflowed)throw Error(`\u7B56\u7565 ${e} \u521D\u59CB\u5316\u671F\u95F4\u7F13\u5B58\u6EA2\u51FA`);if(this.drainPending(r),r.running.fault)throw Error(`\u7B56\u7565 ${e} \u521D\u59CB\u5316\u671F\u95F4\u5F02\u5E38: ${r.running.fault}`);this.saveState(r.running);let i=this.strategies.get(n);if(this.strategies.set(n,r.running),this.pending.delete(n),i)await this.dispose(i,!1);return r.running}async commitPendingUninitialized(e,t){let r=this.requirePending(e,t),n=B(e,r.running.mode);if(r.warmed)throw Error(`\u7B56\u7565 ${e} \u5DF2\u521D\u59CB\u5316\uFF0C\u4E0D\u80FD\u6309\u7B49\u5F85\u72B6\u6001\u63D0\u4EA4`);r.events.length=0;let i=this.strategies.get(n);if(this.strategies.set(n,r.running),this.pending.delete(n),i)await this.dispose(i,!1);return r.running}async abortPending(e,t){let r=this.findPending(e,t);if(!r)return;let n=B(e,r.running.mode);this.pending.delete(n),await this.dispose(r.running,!1)}async start(e,t){let r=this.requireRunning(e,t);if(r.trading)return r;try{if(!r.inited||r.fault)throw Error(`\u7B56\u7565 ${e} \u672A\u5B8C\u6210\u521D\u59CB\u5316${r.fault?`: ${r.fault}`:""}`);if(await this.prepareContractMetadata(r),r.mode==="live")await this.prepareLive(r);try{this.invokeStrategySync(r,"onStart",()=>r.instance.onStart())}catch(n){throw this.failStrategy(r,"onStart",n),n}r.trading=!0,this.syncFrameworkState(r);try{this.saveState(r)}catch(n){throw this.failStrategy(r,"state",n),n}return this.writeLog(r.instance,`started mode=${r.mode}`),this.publishHook("strategy.started",this.strategyIdentity(r)),r}catch(n){throw this.publishHook("strategy.start_failed",{...this.strategyIdentity(r),reason:n instanceof Error?n.message:String(n)}),n}}async startAll(){for(let e of this.strategies.values()){if(!e.enabled)continue;try{await this.start(e.id,e.mode)}catch(t){let r=t instanceof Error?t.message:String(t);console.error(`[cta] ${e.id} \u542F\u52A8\u5931\u8D25: ${r}`)}}}async stop(e,{cancelOrders:t=!1},r){let n=this.requireRunning(e,r);if(n.trading){n.trading=!1,this.syncFrameworkState(n);try{this.invokeStrategySync(n,"onStop",()=>n.instance.onStop())}catch(i){this.failStrategy(n,"onStop",i)}if(this.trySaveState(n),this.writeLog(n.instance,"stopped"),!n.fault)this.publishHook("strategy.stopped",this.strategyIdentity(n))}if(this.syncFrameworkState(n),t)this.cancelAllDirect(n);else{let i=[...n.orders.values()].filter(w).length;if(i>0){let o=this.retainedOrdersMessage(i);this.writeLog(n.instance,o),this.publishHook("strategy.orders_retained",{...this.strategyIdentity(n),activeOrders:i,reason:o})}}return n}async stopAll(e={}){for(let t of this.strategies.values())await this.stop(t.id,e,t.mode)}cancelStrategyOrder(e,t,r){let n=this.requireRunning(e,r),i=n.orders.get(t);if(!i)throw Error(`\u59D4\u6258\u4E0D\u5C5E\u4E8E\u7B56\u7565 ${e}: ${t}`);if(!w(i))return;if(n.mode==="paper")this.cancelOrder(n.instance,t);else{if(!this.deps.live)throw Error("\u5B9E\u76D8\u901A\u9053\u4E0D\u53EF\u7528");this.deps.live.cancelOrder(t)}}cancelPaperOrder(e){if(this.terminalPaperOrders.has(e))return{vtOrderId:e,mode:"paper",result:"terminal"};let t=this.orderOwners.get(e);if(!t||t.mode!=="paper")return null;let r=t.orders.get(e);if(!r)return null;if(!w(r))return{vtOrderId:e,mode:"paper",result:"terminal"};return this.cancelStrategyOrder(t.id,e,t.mode),{vtOrderId:e,mode:"paper",result:"requested"}}async remove(e,t,{clearState:r=!1}={}){let n=this.findRunning(e,t);if(!n)return null;if(await this.stop(n.id,{},n.mode),this.assertOrdersSettled(n.id,n.mode),this.strategies.delete(B(n.id,n.mode)),await this.dispose(n,!r),r)this.deps.stateStore.remove(n.id,n.mode);return n}assertOrdersSettled(e,t){let r=this.requireRunning(e,t);if(r.orders.size>0)throw Error(`\u7B56\u7565 ${e} \u4ECD\u6709 ${r.orders.size} \u7B14\u59D4\u6258\u6216\u6210\u4EA4\u56DE\u62A5\u672A\u5B8C\u6210\uFF0C\u8BF7\u7B49\u5F85\u56DE\u62A5\u6536\u9F50\u540E\u91CD\u8BD5`)}async assertResettable(e,t){let r=this.requireRunning(e,t);if(r.trading||r.enabled)throw Error(`\u7B56\u7565 ${r.id}@${r.mode} \u5C1A\u672A\u505C\u6B62\uFF0C\u8BF7\u5148\u6267\u884C vibek strategy stop ${r.id}@${r.mode}`);if(this.assertOrdersSettled(r.id,r.mode),r.mode!=="live")return r;let n=this.deps.live;if(!n||n.phase!=="running")throw Error("TD \u672A\u8FD0\u884C\uFF0C\u65E0\u6CD5\u91CD\u7F6E Live \u7B56\u7565\u72B6\u6001");let o=(await n.queryOrders(r.instrumentID)).filter(U);if(o.length>0)throw Error(`\u5238\u5546\u5B58\u5728 ${o.length} \u7B14\u6D3B\u52A8\u59D4\u6258\uFF0C\u8BF7\u5148\u4EBA\u5DE5\u5904\u7406`);let s=await n.queryPositions(r.instrumentID);if(s.phase!=="running")throw Error("\u67E5\u8BE2\u5B9E\u76D8\u6301\u4ED3\u5931\u8D25");let a=this.inventoryFromBroker(s.positions,r.instrumentID),d=this.sidePositions(a);if(d.long!==0||d.short!==0)throw Error(`\u5408\u7EA6 ${r.instrumentID} \u4ECD\u6709\u5238\u5546\u6301\u4ED3 \u591A${d.long}/\u7A7A${d.short}\uFF0C\u4E0D\u80FD\u91CD\u7F6E\u672C\u5730\u72B6\u6001`);return r}async close({persist:e=!0}={}){if(e)await this.stopAll({cancelOrders:!0});let t=[...this.strategies.values()],r=[...this.pending.values()].map((n)=>n.running);this.strategies.clear(),this.pending.clear();for(let n of[...t,...r])await this.dispose(n,e);for(let n of this.cleanups.splice(0))n();this.deps.orderRisk.close({persist:e}),this.liveOrders.clear(),this.terminalPaperOrders.clear(),this.liveTradeIds.clear(),this.tradeClaimContext=null,this.timerCursorMs=null,this.eventTimeMs=null}has(e,t){return this.strategies.has(B(e,t))}resolve(e,t){return this.requireRunning(e,t)}setEnabled(e,t,r){let n=this.requireRunning(e,r);if(n.enabled===t)return n;return n.enabled=t,this.publishHook(t?"strategy.enabled":"strategy.disabled",this.strategyIdentity(n)),n}instruments(){return[...new Set([...this.strategies.values()].map((e)=>e.instrumentID))]}instrumentDeclarations(){return[...this.strategies.values()].map((e)=>this.declaration(e))}instrumentDeclarationsWithPending(e,t){let r=this.requirePending(e,t).running;return[...this.strategies.values()].map((n)=>this.declaration(n)).concat(this.declaration(r))}instrumentsWithPending(e,t){let r=this.requirePending(e,t).running;return[...new Set([...this.strategies.values()].map((n)=>n.instrumentID).concat(r.instrumentID))]}handleBar(e){for(let t of this.strategies.values())if(t.instrumentID===e.code&&t.inited)this.enqueue(()=>this.callStrategy(t,"onBar",()=>t.instance.onBar(e)));this.queuePending({kind:"bar",value:e},e.code)}handleTick(e){this.dispatchMarketEvent(e,[])}handleMarketEvent(e,t){this.dispatchMarketEvent(e,t)}handlePaperExternalTrade(e,t){if(e.type!=="order"||e.vtOrderId!==t.vtOrderId||e.vtSymbol!==t.vtSymbol||e.direction!==t.direction||e.offset!==t.offset||e.status!=="allTraded"||e.traded!==e.volume||t.volume!==e.volume)throw Error("\u5916\u90E8 Paper \u8BA2\u5355\u4E0E\u6210\u4EA4\u4E0D\u4E00\u81F4");let r={order:{...e},origin:"external",tradingDay:t.tradingDay,tradedVolume:t.volume,claimable:e.offset==="open",ownerId:null};this.enqueue(()=>{this.dispatchTrades("paper",{...t},{...e},"external",{observed:r,firstTrade:!0,allowPaper:!0})})}handleTimer(e){if(!Number.isFinite(e)||e<0)throw Error("Timer \u65F6\u95F4\u5FC5\u987B\u662F\u975E\u8D1F\u6709\u9650\u6570");let t=Math.floor(e/1000)*1000;if(this.timerCursorMs===null){this.timerCursorMs=t;return}if(t<this.timerCursorMs)throw Error("Timer \u65F6\u95F4\u4E0D\u80FD\u56DE\u9000");for(let r=this.timerCursorMs+1000;r<=t;r+=1000)this.dispatchTimer(r);this.timerCursorMs=t}setTimerClock(e){if(!Number.isFinite(e)||e<0)throw Error("Timer \u65F6\u95F4\u5FC5\u987B\u662F\u975E\u8D1F\u6709\u9650\u6570");this.timerCursorMs=Math.floor(e/1000)*1000}dispatchMarketEvent(e,t){let r=e.tradingDay??e.actionDay??"";this.deps.orderRisk.setTradingDay("paper",r);let n=new Map;for(let i of t){let o=n.get(i.code)??[];o.push(i),n.set(i.code,o)}for(let i of this.strategies.values()){if(!i.inited)continue;let o=i.instrumentID===e.code,s=n.get(i.instrumentID)??[];if(!o&&s.length===0)continue;this.enqueue(()=>{if(o&&i.mode==="paper")this.rollPaperDay(i,r),this.matchPaperOrders(i,e);for(let a of s){if(i.fault)break;this.callStrategy(i,"onBar",()=>i.instance.onBar(a))}if(o)this.callStrategy(i,"onTick",()=>i.instance.onTick(e))})}for(let i of t)this.queuePending({kind:"bar",value:i},i.code);this.queuePending({kind:"tick",value:e},e.code)}snapshot(e={}){return[...this.strategies.values()].map((t)=>{let r=[...t.orders.values()].filter(w).map((n)=>({...n,type:"order"}));return{id:t.id,name:t.name,sourcePath:t.sourcePath,hash:t.hash,loadedAt:t.loadedAt,mode:t.mode,vtSymbol:t.vtSymbol,instrumentID:t.instrumentID,setting:t.setting,enabled:t.enabled,inited:t.inited,trading:t.trading,pos:J(t.inventory),inventory:{...t.inventory},activeOrders:r.length,activeOrderDetails:r,warning:!t.trading&&r.length>0?this.retainedOrdersMessage(r.length):null,fault:t.fault,...e.variables?this.variablesSnapshot(t):{}}})}variablesSnapshot(e){try{return{variables:this.serializeVariables(e),variablesError:null}}catch(t){return{variables:null,variablesError:t instanceof Error?t.message:String(t)}}}riskSnapshot(){return this.deps.orderRisk.snapshot()}sendOrder(e,t,r,n,i){let o=this.requireInstance(e);if(!o.trading||o.fault)return[];if(!Number.isFinite(n)||n<=0||!Number.isInteger(i)||i<=0){let l=`price/volume \u975E\u6CD5 (${n}, ${i})`;return this.writeLog(e,`\u62D2\u7EDD\u59D4\u6258\uFF1A${l}`),this.emitOrderError(o,"invalidRequest",t,r,n,i,l),[]}if(i>this.deps.executionLimits.maxOrderVolume){let l=`\u6570\u91CF ${i} \u8D85\u8FC7\u5355\u7B14\u4E0A\u9650 ${this.deps.executionLimits.maxOrderVolume}`;return this.writeLog(e,`\u62D2\u7EDD\u59D4\u6258\uFF1A${l}`),this.emitRiskRejection(o,"max_order_volume",t,r,n,i,l),this.emitOrderError(o,"maxOrderVolume",t,r,n,i,l),[]}let s=this.resolveOrderParts(o,t,r,n,i);if(s.length===0)return[];if(r==="open"){if([...o.orders.values()].filter((f)=>f.offset==="open"&&w(f)).length>=this.deps.executionLimits.maxActiveOpenOrders){let f=`\u6D3B\u52A8\u5F00\u4ED3\u59D4\u6258\u8FBE\u5230\u4E0A\u9650 ${this.deps.executionLimits.maxActiveOpenOrders}`;return this.writeLog(e,`\u62D2\u7EDD\u5F00\u4ED3\uFF1A${f}`),this.emitRiskRejection(o,"max_active_open_orders",t,r,n,i,f),this.emitOrderError(o,"maxActiveOpenOrders",t,r,n,i,f),[]}}let a=this.roundPrice(o,n);if(!Number.isFinite(a)||a<=0){let l=`price/volume \u975E\u6CD5 (\u820D\u5165\u540E\u4EF7\u683C ${a}\uFF0C\u539F\u59CB ${n})`;return this.writeLog(e,`\u62D2\u7EDD\u59D4\u6258\uFF1A${l}`),this.emitOrderError(o,"invalidRequest",t,r,n,i,l),[]}let d=o.mode==="live"?this.liveTradingDay||o.tradingDay||this.deps.orderRisk.tradingDay("live"):o.tradingDay||this.deps.orderRisk.tradingDay("paper"),c=this.deps.orderRisk.checkOpenDetailed({mode:o.mode,tradingDay:d,vtSymbol:o.vtSymbol,direction:t,offset:r,price:a,volume:i});if(c)return this.writeLog(e,`\u62D2\u7EDD\u5F00\u4ED3\uFF1A${c.message}`),this.emitRiskRejection(o,c.code,t,r,a,i,c.message),this.emitOrderError(o,"riskRejected",t,r,n,i,c.message),[];let u=[];for(let l of s){let f=this.submitPhysical(o,t,l.offset,a,l.volume);if(f)u.push(f)}return u}cancelOrder(e,t){let r=this.requireInstance(e),n=r.orders.get(t);if(!n||!w(n))return;if(r.mode==="paper")this.deps.paperExecution?.onCancelRequested?.(Object.freeze({...n})),n.status="cancelled",n.statusMessage="paper cancelled",this.queueOrder(r,n);else try{this.deps.live?.cancelOrder(t)}catch(i){this.handleLiveError({vtOrderId:t,orderRef:t.slice(4),instrumentID:r.instrumentID,operation:"cancel",message:i instanceof Error?i.message:String(i)})}}cancelAll(e){this.cancelAllDirect(this.requireInstance(e))}liquidatePaper(e,t,r){let n=this.requireRunning(e,"paper");if(n.mode!=="paper")throw Error(`\u7B56\u7565 ${e} \u4E0D\u662F Paper \u6A21\u5F0F`);this.deps.orderRisk.setTradingDay("paper",t.tradingDay??t.actionDay??n.tradingDay);let i=n.trading;n.trading=!1,this.syncFrameworkState(n),this.cancelAllDirect(n);let o=[{direction:"short",offset:"closeYesterday",volume:n.inventory.longYesterday},{direction:"short",offset:"closeToday",volume:n.inventory.longToday},{direction:"long",offset:"closeYesterday",volume:n.inventory.shortYesterday},{direction:"long",offset:"closeToday",volume:n.inventory.shortToday}],s=[];for(let a of o){if(a.volume<=0)continue;let d=a.direction==="long"?t.askPrice1??t.lastPrice:t.bidPrice1??t.lastPrice,c={vtOrderId:`PAPERLIQ.${n.id}.${n.paperSessionId}.${++n.paperOrderCounter}`,vtSymbol:n.vtSymbol,direction:a.direction,offset:a.offset,price:d,volume:a.volume,traded:a.volume,status:"allTraded",statusMessage:r,datetime:t.datetime??this.deps.now()},u=this.paperFill(c,t,a.volume,"marginLiquidation");c.price=u.price,n.orders.set(c.vtOrderId,c),this.orderOwners.set(c.vtOrderId,n),this.emitOrder(n,c);let l={vtTradeId:`PAPERLIQTRADE.${n.id}.${n.paperSessionId}.${++n.paperTradeCounter}`,vtOrderId:c.vtOrderId,vtSymbol:n.vtSymbol,direction:a.direction,offset:a.offset,price:u.price,volume:a.volume,datetime:t.datetime??this.deps.now(),tradingDay:t.tradingDay??t.actionDay??""};this.deps.paperExecution?.onTrade?.(l,u,"marginLiquidation"),this.applyTrade(n,l),s.push(l)}if(i)try{this.invokeStrategySync(n,"onStop",()=>n.instance.onStop())}catch(a){this.failStrategy(n,"onStop",a)}return this.cancelAllDirect(n),this.syncFrameworkState(n),this.scheduleState(n,!0),this.writeLog(n.instance,`\u5F3A\u5236\u5E73\u4ED3\u5E76\u505C\u6B62: ${r}`),s}loadBars(e,t,r){let n=this.requireInitializing(e,"loadBars");if(!t||typeof t!=="object"||Array.isArray(t))throw Error("loadBars request \u5FC5\u987B\u662F\u5BF9\u8C61");if(!Z(t.timeframe))throw Error(`loadBars timeframe \u4E0D\u53D7\u652F\u6301: ${String(t.timeframe)}`);if(!Number.isInteger(t.count)||t.count<=0)throw Error("loadBars count \u5FC5\u987B\u4E3A\u6B63\u6574\u6570");if(n.warmupRequests.length>0)throw Error("\u6BCF\u4E2A\u7B56\u7565\u53EA\u80FD\u767B\u8BB0\u4E00\u4E2A loadBars \u8BF7\u6C42");n.warmupRequests.push({timeframe:t.timeframe,count:t.count,callback:r})}registerEvent(e,t,r){let n=this.requireInitializing(e,"registerEvent");if(t!=="timer"&&t!=="trades")throw Error(`\u4E0D\u652F\u6301\u7684\u7B56\u7565\u4E8B\u4EF6: ${String(t)}`);if(typeof r!=="function")throw Error("\u7B56\u7565\u4E8B\u4EF6 handler \u5FC5\u987B\u662F\u51FD\u6570");let i=n.eventHandlers[t];i.add(r);let o=!0;return()=>{if(!o)return;o=!1,i.delete(r)}}claimOrder(e,t){let r=this.requireInstance(e),n=this.tradeClaimContext;if(r.mode!=="live"&&!(r.mode==="paper"&&n?.allowPaper))return{ok:!1,reason:"\u53EA\u6709 Live \u7B56\u7565\u6216\u4EA4\u4E92\u56DE\u6D4B\u53EF\u4EE5\u8BA4\u9886\u5916\u90E8\u8BA2\u5355"};if(!r.inited||!r.trading||r.fault)return{ok:!1,reason:"\u7B56\u7565\u672A\u5904\u4E8E\u4EA4\u6613\u72B6\u6001"};if(!n||n.running!==r||n.trade.vtOrderId!==t)return{ok:!1,reason:"claimOrder \u53EA\u80FD\u5728\u5F53\u524D\u8BA2\u5355\u7684 trades \u4E8B\u4EF6\u4E2D\u8C03\u7528"};let{observed:i,trade:o}=n;if(i.ownerId!==null||this.orderOwners.has(t))return{ok:!1,reason:"\u8BA2\u5355\u5DF2\u7ECF\u5F52\u5C5E\u7B56\u7565"};let s=i.order;if(!s)return{ok:!1,reason:"\u6210\u4EA4\u5173\u8054\u7684\u8BA2\u5355\u4FE1\u606F\u5C1A\u672A\u5B8C\u6574"};if(!n.firstTrade)return{ok:!1,reason:"\u53EA\u80FD\u8BA4\u9886\u5916\u90E8\u8BA2\u5355\u7684\u9996\u7B14\u65B0\u6210\u4EA4"};if(i.origin!=="external"||s.offset!=="open"||o.offset!=="open")return{ok:!1,reason:"\u53EA\u80FD\u8BA4\u9886\u5916\u90E8\u5F00\u4ED3\u8BA2\u5355"};if(s.vtSymbol!==r.vtSymbol||o.vtSymbol!==r.vtSymbol)return{ok:!1,reason:"\u8BA2\u5355\u5408\u7EA6\u4E0E\u7B56\u7565\u4E0D\u4E00\u81F4"};if(s.direction!==o.direction||o.volume>s.volume||s.status==="rejected")return{ok:!1,reason:"\u8BA2\u5355\u4E0E\u6210\u4EA4\u4FE1\u606F\u4E0D\u4E00\u81F4"};if(r.orders.size>0||Object.values(r.inventory).some((d)=>d!==0))return{ok:!1,reason:"\u7B56\u7565\u5DF2\u6709\u6301\u4ED3\u6216\u672A\u5B8C\u6210\u7684\u8BA2\u5355"};if(r.mode==="live")this.rollLiveDay(r,o.tradingDay);else this.rollPaperDay(r,o.tradingDay);let a={...s,traded:Math.max(s.traded,o.volume)};return i.ownerId=r.id,r.orders.set(t,a),this.orderOwners.set(t,r),this.queueOrder(r,a),this.applyTrade(r,{...o},!0,!1),this.writeLog(r.instance,`claimed external order ${t} on trade ${o.vtTradeId}`),{ok:!0}}writeLog(e,t){this.deps.log(`[cta:${e.strategyName}:${e.mode}] ${t}`)}emitHook(e,t,r){let n=this.requireInstance(e),i=this.eventTimeMs??this.deps.now(),o=er("strategy.event",{...this.strategyIdentity(n),name:t,data:r});fe({type:"hook",id:"00000000-0000-4000-8000-000000000000",event:"strategy.event",account:"a".repeat(64),occurredAt:i,payload:o});try{this.deps.emitHook?.("strategy.event",o,i)}catch(s){this.writeLog(e,`Hook \u6295\u9012\u5931\u8D25 name=${o.name}: ${s instanceof Error?s.message:String(s)}`)}}getCurrentTime(e){return this.requireInstance(e),this.eventTimeMs??this.deps.now()}getContract(e){let t=this.requireInstance(e),r=t.vtSymbol.split(".")[1],n=this.deps.live?.getInstrument(t.instrumentID);if(!n)throw Error(`\u5408\u7EA6 ${t.vtSymbol} Contract \u5C1A\u672A\u51C6\u5907`);if(n.instrumentID.toUpperCase()!==t.instrumentID)throw Error(`\u5408\u7EA6\u4EE3\u7801\u4E0D\u4E00\u81F4\uFF1A\u7B56\u7565 ${t.instrumentID}\uFF0C\u5143\u6570\u636E ${n.instrumentID}`);if(n.exchangeID.toUpperCase()!==r)throw Error(`\u5408\u7EA6\u4EA4\u6613\u6240\u4E0D\u4E00\u81F4\uFF1A\u7B56\u7565 ${r}\uFF0C\u5143\u6570\u636E ${n.exchangeID}`);if(!Number.isFinite(n.priceTick)||n.priceTick<=0||!Number.isSafeInteger(n.volumeMultiple)||n.volumeMultiple<=0||!Number.isSafeInteger(n.minLimitOrderVolume)||n.minLimitOrderVolume<=0||!Number.isSafeInteger(n.maxLimitOrderVolume)||n.maxLimitOrderVolume<n.minLimitOrderVolume||!Number.isFinite(n.longMarginRatio)||n.longMarginRatio<0||!Number.isFinite(n.shortMarginRatio)||n.shortMarginRatio<0)throw Error(`\u5408\u7EA6\u89C4\u683C\u975E\u6CD5: ${t.vtSymbol}`);return Object.freeze({vtSymbol:`${n.instrumentID}.${n.exchangeID}`.toUpperCase(),instrumentID:n.instrumentID.toUpperCase(),exchangeID:n.exchangeID.toUpperCase(),productID:n.productID.toUpperCase(),name:n.instrumentName,priceTick:n.priceTick,size:n.volumeMultiple,minOrderVolume:n.minLimitOrderVolume,maxOrderVolume:n.maxLimitOrderVolume,longMarginRatio:n.longMarginRatio,shortMarginRatio:n.shortMarginRatio,isTrading:n.isTrading===1})}getCommission(e){let t=this.requireInstance(e),r=t.vtSymbol.split(".")[1],n=this.deps.live?.getCommission(t.instrumentID,r);if(!n)throw Error(`\u5408\u7EA6 ${t.vtSymbol} Commission \u5C1A\u672A\u51C6\u5907`);let i=this.getContract(e);if(n.instrumentID.toUpperCase()!==t.instrumentID&&n.instrumentID.toUpperCase()!==i.productID||n.exchangeID&&n.exchangeID.toUpperCase()!==r)throw Error(`\u624B\u7EED\u8D39\u5408\u7EA6\u4E0D\u4E00\u81F4: ${t.vtSymbol}`);if([n.openRatioByMoney,n.openRatioByVolume,n.closeRatioByMoney,n.closeRatioByVolume,n.closeTodayRatioByMoney,n.closeTodayRatioByVolume].some((o)=>!Number.isFinite(o)||o<0))throw Error(`\u624B\u7EED\u8D39\u7387\u975E\u6CD5: ${t.vtSymbol}`);return Object.freeze({open:Object.freeze({ratioByMoney:n.openRatioByMoney,perLot:n.openRatioByVolume}),close:Object.freeze({ratioByMoney:n.closeRatioByMoney,perLot:n.closeRatioByVolume}),closeToday:Object.freeze({ratioByMoney:n.closeTodayRatioByMoney,perLot:n.closeTodayRatioByVolume})})}getPriceTick(e){return this.getContract(e).priceTick}getSize(e){return this.getContract(e).size}async warmupOne(e,t,r=!0,n=!0){e.warmupRequests=[],this.clearEventHandlers(e),e.inited=!1,e.trading=!1,this.syncFrameworkState(e),await this.prepareContractMetadata(e),this.initializing=e;try{this.invokeStrategySync(e,"onInit",()=>e.instance.onInit())}catch(i){throw Error(`\u7B56\u7565 ${e.id} onInit \u5931\u8D25: ${i instanceof Error?i.message:String(i)}`)}finally{this.initializing=null}if(e.warmupRequests.length>0){let i=this.deps.createWarmupProvider();try{for(let o of e.warmupRequests){let s={timeframe:o.timeframe,count:o.count},a=await i.getBars(e.instrumentID,s),d=Et(a,o.timeframe);if(d<o.count)throw Error(`\u5408\u7EA6 ${e.instrumentID} \u9884\u70ED\u6570\u636E\u4E0D\u5B8C\u6574\uFF1A\u9700\u8981 ${o.count} \u6839\u95ED\u5408 ${o.timeframe} Bar\uFF0C\u5B9E\u9645 ${d} \u6839`);for(let c of a)t?.add(zn(c)),this.invokeStrategySync(e,"loadBars callback",()=>o.callback(c));this.writeLog(e.instance,`loadBars ${d} ${o.timeframe} bars / ${a.length} source 1min bars`)}}catch(o){throw Error(`\u7B56\u7565 ${e.id} \u521D\u59CB\u5316\u6570\u636E\u5931\u8D25: ${o instanceof Error?o.message:String(o)}`)}finally{i.destroy()}}if(n)this.restoreState(e);if(this.serializeVariables(e),e.inited=!0,this.syncFrameworkState(e),r)this.saveState(e)}restoreState(e){let t=this.deps.stateStore.read(e.id,e.mode);if(this.observe(e,{type:"state",operation:"read",value:t?{pos:t.pos,inventory:{...t.inventory},variables:structuredClone(t.variables),tradingDay:t.tradingDay}:null}),!t)return;if(t.strategyId!==e.id||t.mode!==e.mode)throw Error(`\u7B56\u7565 ${e.id} \u72B6\u6001\u8EAB\u4EFD\u4E0D\u5339\u914D`);if(t.vtSymbol!==e.vtSymbol)throw Error(`\u7B56\u7565 ${e.id} \u7684\u72B6\u6001\u5C5E\u4E8E ${t.vtSymbol}\uFF0C\u4E0D\u80FD\u6062\u590D\u5230 ${e.vtSymbol}\uFF1B\u8BF7\u4F7F\u7528\u65B0\u7684\u5B9E\u4F8B ID`);if(e.runtime.restoreVariables(t.variables),e.expectedLivePos=t.pos,e.tradingDay=t.tradingDay,e.mode==="paper")e.inventory=t.inventory,this.syncFrameworkState(e);else e.inventory=t.inventory,e.expectedLiveInventory={...e.inventory},this.syncFrameworkState(e)}async prepareLive(e){let t=this.deps.live;if(!t||t.phase!=="running")throw Error("TD \u672A\u8FD0\u884C\uFF0C\u65E0\u6CD5\u542F\u52A8 Live \u7B56\u7565");let r=e.vtSymbol.split(".")[1],n=await t.prepareInstrument(e.instrumentID,r);if(n.exchangeID.toUpperCase()!==r)throw Error(`\u5408\u7EA6\u4EA4\u6613\u6240\u4E0D\u4E00\u81F4\uFF1A\u7B56\u7565 ${r}\uFF0CCTP ${n.exchangeID}`);let i=await t.queryOrders(e.instrumentID);for(let u of i)this.observeLiveOrder(this.orderDataFromBroker(u),u.identity.tradingDay,!1);let o=i.filter(U);if(o.length>0)throw Error(`\u5238\u5546\u5B58\u5728 ${o.length} \u7B14\u6D3B\u52A8\u59D4\u6258\uFF0C\u8BF7\u5148\u4EBA\u5DE5\u5904\u7406`);let s=await t.queryPositions(e.instrumentID);if(s.phase!=="running")throw Error("\u67E5\u8BE2\u5B9E\u76D8\u6301\u4ED3\u5931\u8D25");let a=this.inventoryFromBroker(s.positions,e.instrumentID),d=J(a),c=this.sidePositions(a);if(e.expectedLivePos===null&&(c.long!==0||c.short!==0))throw Error(`\u5408\u7EA6 ${e.instrumentID} \u5DF2\u6709\u5238\u5546\u6301\u4ED3 \u591A${c.long}/\u7A7A${c.short}\uFF0C\u65B0\u7B56\u7565\u62D2\u7EDD\u8BA4\u9886`);if(e.expectedLivePos!==null&&e.expectedLivePos!==d)throw Error(`\u6301\u4ED3\u4E0D\u4E00\u81F4\uFF1A\u672C\u5730 ${e.expectedLivePos}\uFF0C\u5238\u5546 ${d}`);if(e.expectedLiveInventory){let u=this.sidePositions(e.expectedLiveInventory);if(u.long!==c.long||u.short!==c.short)throw Error(`\u6301\u4ED3\u4E0D\u4E00\u81F4\uFF1A\u672C\u5730\u591A${u.long}/\u7A7A${u.short}\uFF0C\u5238\u5546\u591A${c.long}/\u7A7A${c.short}`)}e.inventory=a,e.expectedLivePos=d,e.expectedLiveInventory={...a},e.tradingDay=this.liveTradingDay||s.positions.find((u)=>u.instrumentID===e.instrumentID)?.tradingDay||e.tradingDay,this.syncFrameworkState(e)}async prepareContractMetadata(e){let t=this.deps.live;if(!t||t.phase!=="running")throw Error(`TD \u672A\u8FD0\u884C\uFF0C\u65E0\u6CD5\u521D\u59CB\u5316\u7B56\u7565 ${e.id}`);let r=e.vtSymbol.split(".")[1],n=await t.prepareInstrument(e.instrumentID,r);if(n.exchangeID.toUpperCase()!==r)throw Error(`\u5408\u7EA6\u4EA4\u6613\u6240\u4E0D\u4E00\u81F4\uFF1A\u7B56\u7565 ${r}\uFF0CCTP ${n.exchangeID}`);if(tt(n.exchangeID,n.productID),!this.getContract(e.instance).isTrading)throw Error(`\u5408\u7EA6\u5F53\u524D\u4E0D\u53EF\u4EA4\u6613: ${e.vtSymbol}`);await t.prepareCommission(e.instrumentID,r)}declaration(e){let t=e.vtSymbol.split(".")[1];return{instrumentID:e.instrumentID,exchangeID:t,vtSymbol:e.vtSymbol}}inventoryFromBroker(e,t){let r=cr();for(let n of e){if(n.instrumentID.toUpperCase()!==t.toUpperCase())continue;if(n.hedgeFlag!=="1"&&n.volume!==0)throw Error(`\u6682\u4E0D\u652F\u6301\u975E\u6295\u673A\u6301\u4ED3: ${n.instrumentID}/${n.hedgeFlag}`);if(!Number.isInteger(n.todayVolume)||n.todayVolume<0||!Number.isInteger(n.yesterdayVolume)||n.yesterdayVolume<0||n.todayVolume+n.yesterdayVolume!==n.volume)throw Error(`\u5238\u5546\u6301\u4ED3\u6570\u636E\u975E\u6CD5: ${n.instrumentID}`);if(n.direction==="long")r.longToday+=n.todayVolume,r.longYesterday+=n.yesterdayVolume;else r.shortToday+=n.todayVolume,r.shortYesterday+=n.yesterdayVolume}return r}sidePositions(e){return{long:e.longToday+e.longYesterday,short:e.shortToday+e.shortYesterday}}resolveOrderParts(e,t,r,n,i){if(r==="open"){let c=t==="long"?e.inventory.longToday+e.inventory.longYesterday:e.inventory.shortToday+e.inventory.shortYesterday,u=[...e.orders.values()].filter((l)=>l.offset==="open"&&l.direction===t).reduce((l,f)=>l+this.unsettledOrderVolume(e,f),0);if(c+u+i>this.deps.executionLimits.maxPosition){let l=`\u9884\u8BA1\u6301\u4ED3 ${c+u+i} \u8D85\u8FC7\u4E0A\u9650 ${this.deps.executionLimits.maxPosition}`;return this.writeLog(e.instance,`\u62D2\u7EDD\u5F00\u4ED3\uFF1A${l}`),this.emitRiskRejection(e,"max_position",t,r,n,i,l),this.emitOrderError(e,"maxPosition",t,r,n,i,l),[]}return[{offset:r,volume:i}]}let o=this.availableClose(e,t);if(r==="closeToday"){if(i>o.today)return this.rejectInsufficientClose(e,t,r,n,i,o);return[{offset:r,volume:i}]}if(r==="closeYesterday"){if(i>o.yesterday)return this.rejectInsufficientClose(e,t,r,n,i,o);return[{offset:r,volume:i}]}if(i>o.today+o.yesterday)return this.rejectInsufficientClose(e,t,r,n,i,o);if(!Pr(e.vtSymbol))return[{offset:"close",volume:i}];let s=[],a=Math.min(i,o.yesterday);if(a>0)s.push({offset:"closeYesterday",volume:a});let d=i-a;if(d>0)s.push({offset:"closeToday",volume:d});return s}rejectInsufficientClose(e,t,r,n,i,o){let s=`\u8BF7\u6C42 ${i}\uFF0C\u53EF\u7528\u4ECA ${o.today}/\u6628 ${o.yesterday}`;return this.writeLog(e.instance,`\u62D2\u7EDD\u5E73\u4ED3\uFF1A${s}`),this.emitOrderError(e,"insufficientPosition",t,r,n,i,s),[]}availableClose(e,t){let r=t==="short"?e.inventory.longToday:e.inventory.shortToday,n=t==="short"?e.inventory.longYesterday:e.inventory.shortYesterday,i=0;for(let s of e.orders.values()){if(s.direction!==t||s.offset==="open")continue;let a=this.unsettledOrderVolume(e,s);if(a<=0)continue;if(s.offset==="closeToday")r-=a;else if(s.offset==="closeYesterday")n-=a;else i+=a}r=Math.max(0,r),n=Math.max(0,n);let o=Math.min(n,i);return n-=o,r=Math.max(0,r-(i-o)),{today:r,yesterday:n}}unsettledOrderVolume(e,t){let r=e.tradeVolumeByOrder.get(t.vtOrderId)??0,n=w(t)?t.volume:t.traded;return Math.max(0,n-r)}submitPhysical(e,t,r,n,i){let o;if(e.mode==="paper")o=`PAPER.${e.id}.${e.paperSessionId}.${++e.paperOrderCounter}`;else{let a=this.deps.live;if(!a)return this.emitOrderError(e,"submitFailed",t,r,n,i,"\u5B9E\u76D8\u901A\u9053\u4E0D\u53EF\u7528"),null;try{o=a.submitOrder({strategyId:e.id,instrumentID:e.instrumentID,direction:t==="long"?"buy":"sell",offsetFlag:r,price:n,volume:i}).vtOrderId}catch(d){let c=d instanceof Error?d.message:String(d);return this.writeLog(e.instance,`\u5B9E\u76D8\u62A5\u5355\u5931\u8D25: ${c}`),this.emitOrderError(e,"submitFailed",t,r,n,i,c),null}}let s={vtOrderId:o,vtSymbol:e.vtSymbol,direction:t,offset:r,price:n,volume:i,traded:0,status:"submitting",statusMessage:"",datetime:this.eventTimeMs??this.deps.now()};if(e.mode==="paper"){let a=this.deps.paperExecution?.acceptOrder?.(s)??{ok:!0};if(!a.ok)return this.writeLog(e.instance,`\u62D2\u7EDD\u59D4\u6258\uFF1A${a.reason}`),this.emitOrderError(e,"paperRejected",t,r,n,i,a.reason),null}if(e.orders.set(o,s),this.orderOwners.set(o,e),e.mode==="live"){let a=this.observeLiveOrder(s,this.liveTradingDay||e.tradingDay,!1);a.origin="strategy",a.ownerId=e.id}if(this.deps.orderRisk.recordOrder(e.mode,s,e.tradingDay),e.mode==="paper")this.deps.paperExecution?.onOrderSubmitted?.(Object.freeze({...s}));if(this.queueOrder(e,s),e.mode==="paper")this.enqueue(()=>{if(s.status!=="submitting")return;s.status="notTraded",this.emitOrder(e,s)});return this.scheduleState(e),o}matchPaperOrders(e,t){for(let r of[...e.orders.values()]){if(r.status!=="notTraded")continue;let n=r.direction==="long",i=n?t.askPrice1:t.bidPrice1,o=n?t.askVolume1:t.bidVolume1;if(i===void 0||!Number.isFinite(i)||i<=0)continue;if(o!==void 0&&(!Number.isFinite(o)||o<=0))continue;if(n?r.price<i:r.price>i)continue;let s=r.volume-r.traded,a=this.paperFill(r,t,s,"strategy");r.traded=r.volume,r.status="allTraded",r.statusMessage="paper matched",this.emitOrder(e,r);let d={vtTradeId:`PAPERTRADE.${e.id}.${e.paperSessionId}.${++e.paperTradeCounter}`,vtOrderId:r.vtOrderId,vtSymbol:e.vtSymbol,direction:r.direction,offset:r.offset,price:a.price,volume:s,datetime:t.datetime??this.deps.now(),tradingDay:t.tradingDay??t.actionDay??""};this.deps.paperExecution?.onTrade?.(d,a,"strategy"),this.applyTrade(e,d)}}handleLiveOrder(e){let t=e.vtOrderId;this.observeLiveOrder(this.orderDataFromBroker(e),e.identity.tradingDay);let r=this.orderOwners.get(t);if(!r||r.mode!=="live")return;let n=r.orders.get(t);if(!n)return;n.price=e.price,n.volume=e.volume,n.traded=e.traded,n.status=e.status,n.statusMessage=e.statusMessage,this.emitOrder(r,n),this.scheduleState(r,!0)}observeLiveOrder(e,t,r=!0){let n=this.liveOrders.get(e.vtOrderId);if(!n)n={order:null,origin:"external",tradingDay:t,tradedVolume:0,claimable:r,ownerId:null},this.liveOrders.set(e.vtOrderId,n);return n.order={...e,type:"order"},n.claimable&&=r,n}orderDataFromBroker(e){return{type:"order",vtOrderId:e.vtOrderId,vtSymbol:e.vtSymbol,direction:e.direction,offset:e.offset,price:e.price,volume:e.volume,traded:e.traded,status:e.status,statusMessage:e.statusMessage,datetime:e.datetime}}handleLiveTrade(e){if(!this.rememberTradeId(this.liveTradeIds,e.vtTradeId))return;let t=e.vtOrderId,r=this.orderOwners.get(t),n=this.liveOrders.get(t);if(!n)n={order:null,origin:"external",tradingDay:e.tradingDay,tradedVolume:0,claimable:!1,ownerId:null},this.liveOrders.set(t,n);let i=n.claimable&&n.tradedVolume===0&&this.deps.live?.phase==="running"&&(!this.liveTradingDay||e.tradingDay===this.liveTradingDay);n.tradedVolume+=e.volume,n.claimable=!1;let o={vtTradeId:e.vtTradeId,vtOrderId:t,vtSymbol:e.vtSymbol,direction:e.direction,offset:e.offset,price:e.price,volume:e.volume,datetime:e.datetime,tradingDay:e.tradingDay};if(r?.mode==="live")this.rollLiveDay(r,e.tradingDay),this.applyTrade(r,o);this.dispatchTrades("live",o,n.order,n.origin,{observed:n,firstTrade:i,allowPaper:!1})}handleLiveError(e){let t=this.orderOwners.get(e.vtOrderId);if(!t)return;let r=t.orders.get(e.vtOrderId);if(!r||!w(r))return;if(e.operation==="cancel"){r.statusMessage=`\u64A4\u5355\u5931\u8D25: ${e.message}`,this.emitOrder(t,r),this.scheduleState(t,!0);return}r.status="rejected",r.statusMessage=e.message,this.emitOrder(t,r),this.scheduleState(t,!0)}handleLiveReconciled(e){this.deps.orderRisk.reconcileLive(e),this.liveTradingDay=e.tradingDay;for(let[o,s]of this.liveOrders)if(s.tradingDay<e.tradingDay&&!this.orderOwners.has(o))this.liveOrders.delete(o);for(let o of e.orders)this.observeLiveOrder(this.orderDataFromBroker(o),o.identity.tradingDay,!1);for(let o of e.trades){if(!this.rememberTradeId(this.liveTradeIds,o.vtTradeId))continue;let s=this.liveOrders.get(o.vtOrderId);if(s)s.tradedVolume+=o.volume}if(e.reason!=="reconnect")return;let t=[...this.strategies.values()].filter((o)=>o.mode==="live"&&o.trading);if(t.length===0)return;let r=new Map;for(let o of t){let s=r.get(o.instrumentID)??[];s.push(o),r.set(o.instrumentID,s)}let n=new Map(e.orders.map((o)=>[o.vtOrderId,o]));for(let o of e.orders){if(!U(o)||!r.has(o.instrumentID))continue;let s=this.orderOwners.get(o.vtOrderId);if(!s||!s.trading)throw Error(`\u6062\u590D\u53D1\u73B0\u672A\u5F52\u5C5E\u7684\u6D3B\u52A8\u59D4\u6258: ${o.vtOrderId}`)}for(let o of t)for(let s of o.orders.values())if(w(s)&&!n.has(s.vtOrderId))throw Error(`\u672C\u5730\u6D3B\u52A8\u59D4\u6258\u672A\u51FA\u73B0\u5728\u5238\u5546\u5FEB\u7167: ${s.vtOrderId}`);let i=new Map;for(let o of t)i.set(o,this.inventoryOnTradingDay(o,e.tradingDay));for(let[o,s]of r){let a=this.inventoryFromBroker(e.positions,o),d=s.reduce((c,u)=>{let l=i.get(u);return{longToday:c.longToday+l.longToday,longYesterday:c.longYesterday+l.longYesterday,shortToday:c.shortToday+l.shortToday,shortYesterday:c.shortYesterday+l.shortYesterday}},cr());if(!this.sameInventory(a,d))throw Error(`\u6062\u590D\u6301\u4ED3\u4E0D\u4E00\u81F4 ${o}: \u672C\u5730\u4ECA/\u6628 \u591A${d.longToday}/${d.longYesterday}`+` \u7A7A${d.shortToday}/${d.shortYesterday}\uFF0C\u5238\u5546\u4ECA/\u6628 \u591A${a.longToday}/${a.longYesterday}`+` \u7A7A${a.shortToday}/${a.shortYesterday}`)}for(let[o,s]of i)o.inventory=s,o.expectedLivePos=J(s),o.expectedLiveInventory={...s},o.tradingDay=e.tradingDay,this.syncFrameworkState(o),this.scheduleState(o,!0)}inventoryOnTradingDay(e,t){if(e.tradingDay&&e.tradingDay>t)throw Error(`\u6062\u590D TradingDay \u56DE\u9000: ${e.tradingDay}/${t}`);let r={...e.inventory};if(e.tradingDay&&e.tradingDay!==t)r.longYesterday+=r.longToday,r.longToday=0,r.shortYesterday+=r.shortToday,r.shortToday=0;return r}sameInventory(e,t){return e.longToday===t.longToday&&e.longYesterday===t.longYesterday&&e.shortToday===t.shortToday&&e.shortYesterday===t.shortYesterday}handleLiveFault(e){for(let t of this.strategies.values())if(t.mode==="live"&&t.trading)this.failStrategy(t,"TD",Error(e))}applyTrade(e,t,r=!1,n=!0){let i=t.vtTradeId;if(!this.rememberTradeId(e.seenTrades,i))return;if(this.deps.recordTrade)try{this.deps.recordTrade({strategyId:e.id,name:e.name,mode:e.mode,vtSymbol:e.vtSymbol,trade:{...t},inventory:{...e.inventory},multiplier:this.deps.live?.getInstrument(e.instrumentID)?.volumeMultiple??null})}catch(u){this.writeLog(e.instance,`\u6210\u4EA4\u8BB0\u5F55\u5931\u8D25: ${u instanceof Error?u.message:String(u)}`)}if(this.deps.orderRisk.recordTrade(e.mode,t),this.applyInventory(e.inventory,t.direction,t.offset,t.volume),this.syncFrameworkState(e),e.expectedLivePos=J(e.inventory),e.mode==="live")e.expectedLiveInventory={...e.inventory};let o=(e.tradeVolumeByOrder.get(t.vtOrderId)??0)+t.volume;e.tradeVolumeByOrder.set(t.vtOrderId,o);let s=e.orders.get(t.vtOrderId);if(s)s.traded=Math.max(s.traded,Math.min(s.volume,o));let a={...t},d=s?{...s}:null,c=()=>{if(this.callStrategy(e,"onTrade",()=>(this.observe(e,{type:"trade",value:{...t}}),e.instance.onTrade({...t}))),s)this.pruneTerminalOrder(e,s);if(this.scheduleState(e,!0),e.mode==="paper"&&n)this.dispatchTrades("paper",a,d,"strategy")};if(r)this.scheduleState(e,!0),this.enqueue(c);else c()}applyInventory(e,t,r,n){if(r==="open"){if(t==="long")e.longToday+=n;else e.shortToday+=n;return}let i=t==="short"?"longToday":"shortToday",o=t==="short"?"longYesterday":"shortYesterday";if(r==="closeToday"){e[i]=Math.max(0,e[i]-n);return}if(r==="closeYesterday"){e[o]=Math.max(0,e[o]-n);return}let s=Math.min(e[o],n);e[o]-=s,e[i]=Math.max(0,e[i]-(n-s))}queueOrder(e,t){let r={...t},n=e.tradingDay;this.enqueue(()=>this.emitOrder(e,t,r,n))}emitOrder(e,t,r={...t},n=e.tradingDay){if(this.deps.orderRisk.recordOrder(e.mode,r,n),e.inited)this.callStrategy(e,"onOrder",()=>(this.observe(e,{type:"order",value:{...r,type:"order"}}),e.instance.onOrder({...r,type:"order"})));if(!w(r))this.pruneTerminalOrder(e,t)}emitOrderError(e,t,r,n,i,o,s){let a={type:"error",stage:"submit",code:t,vtSymbol:e.vtSymbol,direction:r,offset:n,price:i,volume:o,message:s,datetime:this.eventTimeMs??this.deps.now()};this.enqueue(()=>this.callStrategy(e,"onOrder",()=>(this.observe(e,{type:"order",value:{...a}}),e.instance.onOrder(a))))}pruneTerminalOrder(e,t){if(e.orders.get(t.vtOrderId)!==t)return;if(w(t))return;if((e.tradeVolumeByOrder.get(t.vtOrderId)??0)<t.traded)return;if(e.mode==="paper")this.deps.paperExecution?.onOrderClosed?.(t),this.terminalPaperOrders.add(t.vtOrderId);e.orders.delete(t.vtOrderId),e.tradeVolumeByOrder.delete(t.vtOrderId),this.orderOwners.delete(t.vtOrderId)}rememberTradeId(e,t){if(e.has(t))return!1;if(e.add(t),e.size>Vo){let r=e.values().next().value;if(r!==void 0)e.delete(r)}return!0}dispatchTimer(e){this.enqueue(()=>{for(let t of this.strategies.values())this.dispatchEvent(t,Object.freeze({type:"timer",now:e}))})}dispatchTrades(e,t,r,n,i){let o=Object.freeze({type:"trades",now:this.eventTimeMs??this.deps.now(),trade:Object.freeze({...t}),order:r?Object.freeze({...r,origin:n}):null});for(let s of this.strategies.values()){if(s.mode!==e)continue;let a=this.tradeClaimContext;this.tradeClaimContext=i?{...i,running:s,trade:o.trade}:null;try{this.dispatchEvent(s,o)}finally{this.tradeClaimContext=a}}}dispatchEvent(e,t){if(!e.inited||e.fault)return;let r=e.eventHandlers[t.type];for(let n of[...r]){if(e.fault)break;if(!r.has(n))continue;this.invokeAtTime(t.now,()=>this.callStrategy(e,`${t.type} event`,()=>n(t)))}}clearEventHandlers(e){for(let t of Object.values(e.eventHandlers))t.clear()}invokeAtTime(e,t){let r=this.eventTimeMs;this.eventTimeMs=e;try{return t()}finally{this.eventTimeMs=r}}rollPaperDay(e,t){if(!t||t===e.tradingDay)return;if(e.tradingDay){for(let r of e.orders.values()){if(!w(r))continue;r.status="cancelled",r.statusMessage="paper trading day changed",this.queueOrder(e,r)}e.inventory.longYesterday+=e.inventory.longToday,e.inventory.longToday=0,e.inventory.shortYesterday+=e.inventory.shortToday,e.inventory.shortToday=0}e.tradingDay=t,this.scheduleState(e,!0)}rollLiveDay(e,t){if(!t||t===e.tradingDay)return;let r=this.inventoryOnTradingDay(e,t);e.inventory=r,e.expectedLiveInventory={...r},e.expectedLivePos=J(r),e.tradingDay=t,this.syncFrameworkState(e)}roundPrice(e,t){let r=this.getPriceTick(e.instance);return Number((Math.round(t/r)*r).toFixed(10))}paperFill(e,t,r,n){let i=(e.direction==="long"?t.askPrice1:t.bidPrice1)??e.price,o=this.deps.paperExecution?.fillOrder?.(e,t,r,n)??{referencePrice:i,price:i};if(!Number.isFinite(o.referencePrice)||o.referencePrice<=0||!Number.isFinite(o.price)||o.price<=0)throw Error(`Paper \u6210\u4EA4\u4EF7\u975E\u6CD5: ${o.referencePrice}/${o.price}`);return o}cancelAllDirect(e){for(let t of e.orders.values()){if(!w(t))continue;if(e.mode==="paper")this.cancelOrder(e.instance,t.vtOrderId);else try{this.deps.live?.cancelOrder(t.vtOrderId)}catch(r){console.error(`[cta] ${e.id} \u64A4\u5355\u5931\u8D25: ${r instanceof Error?r.message:String(r)}`)}}}retainedOrdersMessage(e){return`\u7B56\u7565\u5DF2\u505C\u6B62\uFF0C\u4ECD\u6709 ${e} \u7B14\u59D4\u6258\u672A\u64A4\u9500\uFF0C\u53EF\u80FD\u7EE7\u7EED\u6210\u4EA4\uFF0C\u8BF7\u624B\u52A8\u64A4\u5355\u3002`}scheduleState(e,t=!1){if(t){e.stateTimer?.(),e.stateTimer=null,this.trySaveState(e);return}if(e.stateTimer)return;e.stateTimer=this.deps.schedule(()=>{e.stateTimer=null,this.trySaveState(e)},qo)}saveState(e){let t=this.serializeVariables(e);this.deps.stateStore.write({strategyId:e.id,vtSymbol:e.vtSymbol,mode:e.mode,bundleHash:e.hash,pos:J(e.inventory),variables:t,inventory:e.inventory,tradingDay:e.tradingDay}),this.observe(e,{type:"state",operation:"write",value:{pos:J(e.inventory),inventory:{...e.inventory},variables:t,tradingDay:e.tradingDay}})}serializeVariables(e){return Un(e.runtime.getStateVariables(),`\u7B56\u7565 ${e.id} variables`)}trySaveState(e){try{this.saveState(e)}catch(t){if(console.error(`[cta] ${e.id} \u72B6\u6001\u4FDD\u5B58\u5931\u8D25: ${t instanceof Error?t.message:String(t)}`),e.trading)this.failStrategy(e,"state",t)}}callStrategy(e,t,r){if(e.fault)return;try{this.invokeStrategySync(e,t,r),this.scheduleState(e)}catch(n){this.failStrategy(e,t,n)}}failStrategy(e,t,r){let n=r instanceof Error?r.message:String(r);if(e.fault)return;e.fault=`${t}: ${n}`,this.observe(e,{type:"fault",callback:t,message:n}),e.trading=!1,e.inited=!1,this.clearEventHandlers(e),this.syncFrameworkState(e),this.cancelAllDirect(e),console.error(`[cta] ${e.id} ${t} \u5F02\u5E38\uFF0C\u7B56\u7565\u5DF2\u505C\u6B62: ${n}`),this.publishHook("strategy.faulted",{...this.strategyIdentity(e),callback:t,reason:n})}emitRiskRejection(e,t,r,n,i,o,s){let a=this.deps.orderRisk.tradingDay(e.mode)||e.tradingDay||null;this.publishHook("risk.order_rejected",{source:"strategy",riskCode:t,mode:e.mode,vtSymbol:e.vtSymbol,tradingDay:a,direction:r,offset:n,price:i,volume:o,reason:s,strategyId:e.id})}strategyIdentity(e){return{strategyId:e.id,mode:e.mode,vtSymbol:e.vtSymbol}}publishHook(e,t){try{this.deps.emitHook?.(e,t)}catch(r){console.error(`[hooks] \u4E8B\u4EF6\u6295\u9012\u5931\u8D25 event=${e}: ${r instanceof Error?r.message:String(r)}`)}}enqueue(e){let t=this.eventTimeMs;if(this.eventQueue.push(t===null?e:()=>this.invokeAtTime(t,e)),this.dispatching)return;this.dispatching=!0;try{while(this.eventQueue.length>0)this.eventQueue.shift()()}finally{this.dispatching=!1}}queuePending(e,t){for(let r of this.pending.values()){if(r.running.instrumentID!==t)continue;if(r.events.length>=Vn){r.overflowed=!0;continue}r.events.push(e)}}drainPending(e){while(e.events.length>0){let t=e.events.splice(0);for(let r of t){if(r.kind==="bar"){if(e.replayedBars.has(zn(r.value)))continue;this.callStrategy(e.running,"onBar",()=>e.running.instance.onBar(r.value))}else this.callStrategy(e.running,"onTick",()=>e.running.instance.onTick(r.value));if(e.running.fault)return}}}assertLiveInstrumentOwner(e){if(e.mode!=="live")return;let t=[...this.strategies.values()].find((r)=>B(r.id,r.mode)!==B(e.id,e.mode)&&r.mode==="live"&&r.instrumentID===e.instrumentID);if(t)throw Error(`Live \u5408\u7EA6 ${e.instrumentID} \u5DF2\u7531\u7B56\u7565 ${t.id} \u5360\u7528`)}requireInitializing(e,t){let r=this.requireInstance(e);if(this.initializing!==r)throw Error(`${t} \u53EA\u80FD\u5728 onInit() \u4E2D\u8C03\u7528`);return r}requireInstance(e){let t=this.instanceMap.get(e);if(!t)throw Error("\u672A\u77E5\u7B56\u7565\u5B9E\u4F8B");return t}findRunning(e,t){return this.strategies.get(B(e,t))??null}requireRunning(e,t){let r=this.findRunning(e,t);if(!r)throw Error(`\u7B56\u7565\u5B9E\u4F8B\u4E0D\u5B58\u5728: ${e}@${t}`);return r}findPending(e,t){return this.pending.get(B(e,t))??null}requirePending(e,t){let r=this.findPending(e,t);if(!r)throw Error(`\u7B56\u7565 ${e}@${t} \u6CA1\u6709\u5F85\u63D0\u4EA4\u53D8\u66F4`);return r}async dispose(e,t=!0){if(e.stateTimer?.(),e.stateTimer=null,t&&e.inited)this.trySaveState(e);this.instanceMap.delete(e.instance),this.clearEventHandlers(e);for(let r of e.orders.keys())this.orderOwners.delete(r)}invokeSync(e,t){let r=t();if(r&&typeof r.then==="function")throw Promise.resolve(r).catch(()=>{return}),Error(`${e} \u4E0D\u5141\u8BB8\u8FD4\u56DE Promise`)}invokeStrategySync(e,t,r){this.syncFrameworkState(e),this.observe(e,{type:"callback",callback:t,stage:"begin"});try{this.invokeSync(t,r)}finally{this.syncFrameworkState(e),this.observe(e,{type:"callback",callback:t,stage:"end"})}}observe(e,t){this.deps.observe({...t,strategyId:e.id,now:this.eventTimeMs??this.deps.now()})}syncFrameworkState(e){e.runtime.setRuntimeState({inited:e.inited,trading:e.trading,pos:J(e.inventory)})}}var jn=20,Yo=1000,Q="vibek-test",Wo={maxOrderVolume:1000,maxPosition:1e4,maxActiveOpenOrders:1000},Gn={dailyLimits:{totalOrderLimit:1e5,totalCancelLimit:1e5,totalTradeLimit:1e5,instrumentOrderLimit:1e5,instrumentCancelLimit:1e5,instrumentTradeLimit:1e5},duplicateOrderLimit:1e5};class ie{definition;fixture;events=[];orderEvents=[];tradeEvents=[];logs=[];hooks=[];submissions=[];cancelRequests=[];broker;callbackCounts={onInit:0,onStart:0,onStop:0,onTick:0,onBar:0};dataDir;stateStore;clock;traceRecorder;faults=[];aggregator=new Ve({timeframes:["1min"]});barHistory=[];warmupSupplied=!1;paperSessionSequence=0;mode;setting;initialState;brokerState;executionLimits;riskSettings;paperExecution;runtime;running;live;gatewayControl;eventCounter=0;nextEventTimeMs;initialized=!1;initialStateWritten=!1;disposed=!1;firstSdkOrderViolation;constructor(e,t,r={}){this.definition=e;this.fixture=t;if(this.mode=r.mode??"live",r.execution!==void 0&&r.execution!=="scripted"&&r.execution!=="ctp")throw Error("Unknown test execution model");if(r.execution==="ctp"&&this.mode!=="live")throw Error("CTP execution requires live mode");if(r.execution==="ctp"&&r.brokerState)throw Error("CTP execution uses gatewayState");if(r.brokerState&&this.mode!=="live")throw Error("Broker state requires live mode");if(r.paperExecution&&this.mode!=="paper")throw Error("Paper execution hooks require paper mode");if(r.execution!=="ctp"&&(r.gatewayState||r.gatewaySession))throw Error("Gateway settings require CTP execution");this.setting=r.setting===void 0?ce(t.setting,"setting"):ce(r.setting,"setting"),this.initialState=r.initialState,this.brokerState=r.brokerState===void 0?void 0:structuredClone(r.brokerState),this.executionLimits=Jo(r.executionLimits),this.riskSettings=Qo(r.riskLimits),this.paperExecution=r.paperExecution,this.clock=new Ht(Ke(t)),this.traceRecorder=new Lt(()=>this.clock.now);let{paperExecution:n,...i}=r;if(this.traceRecorder.record("context",{fixture:{vtSymbol:t.vtSymbol,instrument:{priceTick:t.priceTick,size:t.size,name:t.name,minOrderVolume:t.minOrderVolume,maxOrderVolume:t.maxOrderVolume,longMarginRatio:t.longMarginRatio,shortMarginRatio:t.shortMarginRatio,isTrading:t.isTrading},...t.commission?{commission:t.commission}:{},setting:t.setting,seedPrice:t.seedPrice,tradingDay:t.tradingDay},options:i,...n?{customPaperExecution:!0}:{}}),r.execution==="ctp")this.live=new _e(t,this.clock,this.traceRecorder,r,{submissions:this.submissions,cancelRequests:this.cancelRequests});this.nextEventTimeMs=this.clock.now;let o={holdReports:()=>this.requireLive().holdReports(),resumeReports:()=>this.requireLive().resumeReports(),pendingReports:()=>this.requireLive().pendingReports(),deliverReport:(s)=>this.requireLive().deliverReport(s),repeatReport:(s)=>this.requireLive().repeatReport(s),snapshot:()=>this.requireLive().snapshot(),failNextSubmit:(s)=>this.requireLive().failNextSubmit(s),rejectSubmit:(s,a)=>this.requireLive().rejectSubmit(s,a),acknowledge:(s)=>this.requireLive().acknowledge(s),partialFill:(s,a,d)=>this.requireLive().partialFill(s,a,d),fill:(s,a)=>this.requireLive().fill(s,a),reject:(s,a)=>this.requireLive().reject(s,a),cancel:(s,a)=>this.requireLive().cancel(s,a),failNextCancel:(s)=>this.requireLive().failNextCancel(s),rejectCancel:(s,a)=>this.requireLive().rejectCancel(s,a),emitExternalOrder:(s)=>this.requireLive().emitExternalOrder(s),emitOrder:(s)=>this.requireLive().emitOrder(s),emitTrade:(s)=>this.requireLive().emitTrade(s),disconnect:()=>this.requireLive().disconnect(),reconcile:(s)=>this.requireLive().reconcile(s),fault:(s)=>this.requireLive().fault(s)};this.broker=this.observeCommands(o,"broker",["snapshot","pendingReports"]),this.dataDir=Uo(Ko(Go(),"vibek-strategy-test-runtime-")),this.stateStore=new $e(this.dataDir)}initialize(e={}){return this.traceRecorder.input({type:"initialize",...e},()=>this.initializeRuntime(e))}async initializeRuntime(e){if(this.disposed)throw Error("\u6D4B\u8BD5 Runtime \u5DF2\u91CA\u653E");if(this.initialized)throw Error("\u6D4B\u8BD5 Runtime \u5DF2\u521D\u59CB\u5316");if(e.warmupBars){let t=e.warmupBars.map((r,n)=>H(this.fixture,r,n));Ie(t,this.clock.now,this.fixture.instrumentID),this.barHistory.push(...t),this.warmupSupplied=!0}this.seedInitialState(),await this.createRuntime(),await this.runtime.warmup(),this.runtime.setTimerClock(this.clock.now),this.initialized=!0}async start(){this.requireInitialized(),await this.traceRecorder.input({type:"start"},()=>this.runtime.start(Q,this.mode))}async stop(){this.requireInitialized(),await this.traceRecorder.input({type:"stop"},()=>this.runtime.stop(Q,{},this.mode))}cancelOrder(e){this.requireInitialized(),this.traceRecorder.input({type:"cancelOrder",vtOrderId:e},()=>{this.runtime.cancelStrategyOrder(Q,e,this.mode)})}async restart(){this.requireInitialized(),await this.traceRecorder.input({type:"restart"},async()=>{await this.runtime.stop(Q,{},this.mode),await this.rebuildRuntime()})}async crashAndRestart(){this.requireInitialized(),await this.traceRecorder.input({type:"crashAndRestart"},()=>this.rebuildRuntime(!1))}setTime(e){if(this.disposed)throw Error("\u6D4B\u8BD5 Runtime \u5DF2\u91CA\u653E");let t=T(e,"\u6D4B\u8BD5\u65F6\u95F4");this.traceRecorder.input({type:"setTime",datetime:t},()=>{if(this.initialized)this.advanceClock(t);else this.clock.now=t}),this.nextEventTimeMs=t}advanceTime(e){if(this.disposed)throw Error("\u6D4B\u8BD5 Runtime \u5DF2\u91CA\u653E");let t=T(e,"\u63A8\u8FDB\u65F6\u95F4"),r=this.clock.now+t;if(!Number.isSafeInteger(r))throw Error("\u63A8\u8FDB\u540E\u7684\u6D4B\u8BD5\u65F6\u95F4\u8D85\u8FC7\u5B89\u5168\u6574\u6570\u8303\u56F4");this.traceRecorder.input({type:"advanceTime",milliseconds:e},()=>this.advanceClock(r)),this.nextEventTimeMs=r}pushBar(e,t={}){this.requireInitialized();let r=t.datetime??(e.barTime===void 0?Math.max(this.nextEventTimeMs,((this.barHistory.at(-1)?.barTime??-120)+120)*1000):(e.barTime+60)*1000),n=H(this.fixture,e,this.eventCounter,Math.floor(r/60000)*60-60);this.validateClosedBars([n],r),this.traceRecorder.input({type:"bar",value:n,datetime:r},()=>{this.recordEventTime(r),this.eventCounter++,this.aggregator.completeThrough(r),this.dispatchBars(this.mergeClosedBars(this.takeCompletedBars(),[n]))})}pushTick(e){this.pushMarketEvent(e,[])}pushMarketEvent(e,t){this.requireInitialized();let r=De(this.fixture,e,this.eventCounter,this.nextEventTimeMs);if(r.code!==this.fixture.instrumentID)throw Error("\u6D4B\u8BD5 Tick \u5408\u7EA6\u4E0E fixture \u4E0D\u5339\u914D");let n=t.map((o,s)=>H(this.fixture,o,s)),i=r.receivedAt??r.datetime;if(r.datetime>i||i-r.datetime>dt)throw Error("\u6D4B\u8BD5 Tick \u4EA4\u4ED8\u65F6\u95F4\u5FC5\u987B\u4F4D\u4E8E\u884C\u60C5\u65F6\u95F4\u4E4B\u540E\u7684 30 \u79D2\u4EE5\u5185");this.validateClosedBars(n,i),this.traceRecorder.input({type:"market",tick:r,closedBars:n},()=>{this.recordEventTime(i),this.eventCounter++,this.aggregator.pushTick(r);let o=this.mergeClosedBars(this.takeCompletedBars(),n);this.rememberBars(o);for(let s of o)this.traceRecorder.record("bar",s);this.runtime.handleMarketEvent(r,o)})}activeOrders(){if(this.requireInitialized(),!this.running)throw Error("\u6D4B\u8BD5 Runtime \u7684\u7B56\u7565\u5B9E\u4F8B\u4E0D\u5B58\u5728");return[...this.running.orders.values()].filter(w).map((e)=>({...e}))}snapshot(){this.requireInitialized();let e=this.runtime.snapshot().find((t)=>t.id===Q);if(!e||!this.running)throw Error("\u6D4B\u8BD5 Runtime \u7684\u7B56\u7565\u5B9E\u4F8B\u4E0D\u5B58\u5728");return{inited:e.inited,trading:e.trading,pos:e.pos,activeOrders:e.activeOrders,fault:e.fault,variables:ce(this.running.runtime.getStateVariables(),"variables"),inventory:{...this.running.inventory},now:this.clock.now}}get trace(){return this.traceRecorder.events}get gateway(){if(this.disposed)throw Error("\u6D4B\u8BD5 Runtime \u5DF2\u91CA\u653E");if(!(this.live instanceof _e))throw Error('Gateway controls require execution="ctp"');return this.gatewayControl??=this.observeCommands(this.live.gateway,"gateway",["pendingRequests"])}expectFault(e){let t=this.faults.find((r)=>!r.verified&&r.message===e);if(!t)throw Error(`\u672A\u53D1\u751F\u5F85\u9A8C\u8BC1\u7684 fault: ${e}`);t.verified=!0,this.traceRecorder.record("input",{type:"expectFault",message:e})}settleActiveOrders(){if(this.mode==="live"){if(!(this.live instanceof Oe))throw Error("CTP orders require explicit gateway reports");this.live.settleActiveOrders()}else for(let e of this.activeOrders())this.cancelOrder(e.vtOrderId)}assertHealthy(e){let t=this.snapshot();if(t.fault)throw Error(`${e}\u540E\u7B56\u7565 fault: ${t.fault}`);if(this.firstSdkOrderViolation)throw Error(`${e}\u89E6\u53D1 SDK \u975E\u6CD5\u4E0B\u5355: ${this.firstSdkOrderViolation}`)}async dispose(){if(!this.disposed){this.disposed=!0;try{await this.runtime?.close()}finally{if(this.live instanceof _e)this.live.close();this.traceRecorder.close(),jo(this.dataDir,{recursive:!0,force:!0})}}let e=this.faults.filter((t)=>!t.verified);if(e.length)throw Error(`\u672A\u9A8C\u8BC1\u7684\u7B56\u7565 fault: ${e.map((t)=>t.message).join("; ")}`)}async createRuntime(){let e=this.stateStore.read(Q,this.mode),t=e?.inventory??de(),r={...this.fixture,tradingDay:e?.tradingDay||this.fixture.tradingDay};this.live??=new Oe(r,t,{order:0,trade:0},()=>this.clock.now,{submissions:this.submissions,cancelRequests:this.cancelRequests,record:(i,o)=>this.traceRecorder.record(i,o)},this.brokerState);let n=new He({settings:this.riskSettings,stateStore:new dr(this.dataDir),schedule:(i,o)=>this.clock.schedule(this.traceRecorder.bind(i),o)});n.setTradingDay("paper",r.tradingDay),this.runtime=new mr({createWarmupProvider:()=>new Bt(r,this.barHistory,this.clock.now,!this.warmupSupplied),stateStore:this.stateStore,live:this.live,paperExecution:{...this.paperExecution,onOrderSubmitted:(i)=>{let o={vtOrderId:i.vtOrderId,direction:i.direction,offset:i.offset,price:i.price,volume:i.volume};this.submissions.push(o),this.traceRecorder.record("submission",o)},onCancelRequested:(i)=>{this.cancelRequests.push(i.vtOrderId),this.traceRecorder.record("cancel",{vtOrderId:i.vtOrderId})}},orderRisk:n,executionLimits:this.executionLimits,log:(i)=>this.recordLog(i),now:()=>this.clock.now,schedule:(i,o)=>this.clock.schedule(this.traceRecorder.bind(i),o),createPaperSessionId:()=>String(++this.paperSessionSequence),observe:(i)=>this.observe(i),emitHook:(i,o,s)=>{if(i!=="strategy.event")return;let a=structuredClone({...o,occurredAt:s??this.clock.now});this.hooks.push(a),this.events.push({type:"hook",value:a,now:a.occurredAt}),this.traceRecorder.record("hook",a)}}),await this.live.connect(),this.running=this.runtime.addRestored({sourcePath:"strategy.ts",hash:"a".repeat(64),artifact:"strategy-test",loadedAt:new Date(0).toISOString(),mode:this.mode,definition:this.definition,instance:{id:Q,vtSymbol:this.fixture.vtSymbol,setting:this.setting}})}observe(e){if(this.traceRecorder.record(e.type,e),e.type==="callback"&&e.stage==="begin"&&Object.hasOwn(this.callbackCounts,e.callback))this.callbackCounts[e.callback]++;else if(e.type==="order"){let t=Xo(e.value);if(t.type==="error"&&(t.code==="invalidRequest"||t.code==="insufficientPosition"))this.firstSdkOrderViolation??=`${t.code}: ${t.message}`;this.orderEvents.push(t),this.events.push({type:"order",value:t,now:e.now})}else if(e.type==="trade")this.tradeEvents.push({...e.value}),this.events.push({type:"trade",value:{...e.value},now:e.now});else if(e.type==="fault")this.faults.push({message:`${e.callback}: ${e.message}`,verified:!1})}recordLog(e){let t=Zo(this.logs,e);this.traceRecorder.record("log",{message:t})}async rebuildRuntime(e=!0){await this.runtime.close({persist:e}),this.runtime=void 0,this.running=void 0,this.aggregator.reset(),this.initialized=!1,await this.createRuntime(),await this.runtime.warmup(),this.runtime.setTimerClock(this.clock.now),this.initialized=!0}recordEventTime(e){let t=e+60000;if(!Number.isSafeInteger(t))throw Error("\u884C\u60C5\u65F6\u95F4\u8D85\u8FC7\u5B89\u5168\u6574\u6570\u8303\u56F4");if(e<this.clock.now)throw Error("\u884C\u60C5\u65F6\u95F4\u4E0D\u80FD\u56DE\u9000");this.advanceClock(e),this.nextEventTimeMs=t}advanceClock(e){this.clock.advanceTo(e,this.initialized?()=>{this.traceRecorder.record("timer",{now:this.clock.now}),this.runtime.handleTimer(this.clock.now),this.aggregator.completeThrough(this.clock.now-dt),this.dispatchBars(this.takeCompletedBars())}:void 0)}takeCompletedBars(){let e=[...this.aggregator.getCompletedBars()];return this.aggregator.clearCompletedBars(),e.filter((t)=>t.barTime>(this.barHistory.at(-1)?.barTime??-1))}validateClosedBars(e,t){if(Ie(e,t,this.fixture.instrumentID),e.some((n)=>n.barTime<=(this.barHistory.at(-1)?.barTime??-1)))throw Error("\u95ED\u5408 Bar \u65F6\u95F4\u5FC5\u987B\u665A\u4E8E\u5DF2\u56DE\u653E\u5386\u53F2");let r=this.aggregator.getCurrentBar("1min");if(r&&t>=(r.barTime+60)*1000+dt&&e.some((n)=>n.barTime===r.barTime))throw Error("\u663E\u5F0F Bar \u7684\u4EA4\u4ED8\u665A\u4E8E\u81EA\u52A8\u95ED\u5408\u671F\u9650\uFF0C\u4E0D\u80FD\u66FF\u6362\u5DF2\u5230\u671F\u7684 Bar")}mergeClosedBars(e,t){let r=new Map(e.map((n)=>[n.barTime,n]));for(let n of t)r.set(n.barTime,n);return[...r.values()].sort((n,i)=>n.barTime-i.barTime)}rememberBars(e){this.barHistory.push(...e.map((t)=>({...t})))}dispatchBars(e){this.rememberBars(e);for(let t of e)this.traceRecorder.record("bar",t),this.runtime.handleBar(t)}seedInitialState(){if(this.initialStateWritten||!this.initialState)return;let e=We(this.initialState.inventory),t=this.initialState.variables===void 0?{}:ce(this.initialState.variables,"initialState.variables");this.stateStore.write({strategyId:Q,vtSymbol:this.fixture.vtSymbol,mode:this.mode,bundleHash:"a".repeat(64),pos:Mr(e),variables:t,inventory:e,tradingDay:this.fixture.tradingDay}),this.initialStateWritten=!0}requireInitialized(){if(this.disposed)throw Error("\u6D4B\u8BD5 Runtime \u5DF2\u91CA\u653E");if(!this.initialized||!this.runtime)throw Error("\u6D4B\u8BD5 Runtime \u5C1A\u672A initialize()")}requireLive(){if(this.requireInitialized(),this.mode!=="live"||!(this.live instanceof Oe))throw Error('broker \u63A7\u5236\u53EA\u9002\u7528\u4E8E mode="live"\u3001execution="scripted" \u7684\u6D4B\u8BD5 Runtime');return this.live}observeCommands(e,t,r){return new Proxy(e,{get:(n,i)=>{let o=Reflect.get(n,i);if(typeof o!=="function"||!Object.hasOwn(n,i)||r.includes(String(i)))return o;return(...s)=>this.traceRecorder.input({type:t,method:i,args:s},()=>Reflect.apply(o,n,s))}})}}function Jo(e){let t={...Wo,...e};return{maxOrderVolume:_(t.maxOrderVolume,"executionLimits.maxOrderVolume"),maxPosition:_(t.maxPosition,"executionLimits.maxPosition"),maxActiveOpenOrders:_(t.maxActiveOpenOrders,"executionLimits.maxActiveOpenOrders")}}function Qo(e){let t={...Gn.dailyLimits,...e?.dailyLimits};for(let r of Object.keys(t))_(t[r],`riskLimits.dailyLimits.${r}`);return{dailyLimits:t,duplicateOrderLimit:_(e?.duplicateOrderLimit??Gn.duplicateOrderLimit,"riskLimits.duplicateOrderLimit")}}function Zo(e,t){let r=es(ts(t),Yo);if(e.push(r),e.length>jn)e.splice(0,e.length-jn);return r}function Xo(e){return{...e}}function es(e,t){let r=Buffer.from(e);if(r.length<=t)return e;return`${r.subarray(0,t).toString("utf8")}...`}function ts(e){return e.replace(/\bsk-[A-Za-z0-9_-]{6,}\b/g,"[redacted]").replace(/((?:api[_ -]?key|authorization|access[_ -]?token)\s*[:=]\s*)\S+/gi,"$1[redacted]")}async function pr(e,t,r){await e.initialize(),await e.start();for(let n of[0,1,-1,2,-2,0]){if(e.pushTick({lastPrice:Math.max(t.priceTick,t.seedPrice+n*t.priceTick),askVolume1:1,bidVolume1:1}),e.advanceTime(1500),r==="live")for(let i of e.activeOrders()){if(i.status==="submitting")e.broker.acknowledge(i.vtOrderId);if(!e.activeOrders().some((o)=>o.vtOrderId===i.vtOrderId))continue;if(i.volume-i.traded>1)e.broker.partialFill(i.vtOrderId,1);else e.broker.fill(i.vtOrderId)}e.advanceTime(60000),e.assertHealthy("\u786E\u5B9A\u6027\u56DE\u653E")}return await e.stop(),e.settleActiveOrders(),await e.restart(),await e.start(),e.pushTick({lastPrice:t.seedPrice}),e.advanceTime(1000),await e.stop(),e.settleActiveOrders(),e.assertHealthy("\u786E\u5B9A\u6027\u91CD\u542F"),{trace:e.trace,submissions:e.submissions,cancelRequests:e.cancelRequests,events:e.events,orderEvents:e.orderEvents,tradeEvents:e.tradeEvents,hooks:e.hooks,logs:e.logs,snapshot:e.snapshot()}}import{isDeepStrictEqual as Yn,inspect as Wn}from"util";class ft extends Error{step;scenario;trace;constructor(e,t,r,n){super(`Strategy scenario failed at step ${e}${t.seed===void 0?"":` (seed ${t.seed})`}: ${n instanceof Error?n.message:String(n)}
72
+ Replay: ${Jn(t)}`,{cause:n});this.step=e;this.scenario=t;this.trace=r;this.name="StrategyScenarioError"}}async function gr(e,t,r={}){if(yt(t),t.context?.customPaperExecution&&!r.paperExecution)throw Error("Custom Paper hooks must be supplied to replay this scenario");let n=new ie(e.strategy,Y(t.context?.fixture??e.fixture),{...t.context?.options,...r}),i={...t,context:n.trace[0].value},o=0,s=new Map;try{for(;o<t.steps.length;o++){let d=t.steps[o];if(d.at!==void 0)n.setTime(d.at);if(d.action.type==="await"){let c=s.get(d.action.task);if(!c)throw Error(`Scenario task does not exist: ${d.action.task}`);let u=await c;if(s.delete(d.action.task),d.action.error===void 0){if("error"in u)throw u.error}else if(!("error"in u)||(u.error instanceof Error?u.error.message:String(u.error))!==d.action.error)throw Error(`Scenario task did not reject with: ${d.action.error}`)}else if(d.task)s.set(d.task,Kn(n,d.action).then(()=>({}),(c)=>({error:c})));else await Kn(n,d.action)}let a={...t.seed===void 0?{}:{seed:t.seed},trace:n.trace,snapshot:n.snapshot(),submissions:structuredClone(n.submissions),cancelRequests:[...n.cancelRequests]};return await n.dispose(),a}catch(a){try{await n.dispose()}catch(d){if(d!==a)a=AggregateError([a,d],String(a))}throw new ft(o,i,n.trace,a)}}async function rs(e,t,r={}){let n=await gr(e,t,r),i=await gr(e,t,r);try{if(fr(n.trace,i.trace),!Yn(n.snapshot,i.snapshot))throw Error(`Strategy replay snapshot differs:
51
73
  ${Wn({expected:n.snapshot,actual:i.snapshot},{depth:8})}`)}catch(o){let s={...t,context:i.trace[0].value};throw new ft(t.steps.length,s,i.trace,o)}return n}function fr(e,t){for(let r=0;r<Math.max(e.length,t.length);r++)if(!Yn(e[r],t[r]))throw Error(`Strategy replay first differs at trace[${r}] (sequence ${r+1}):
52
- ${Wn({expected:e[r],actual:t[r]},{depth:8})}`)}function rs(e,t){let r=e.trace,n=new Map;for(let s of r)if(s.type==="completion"){let a=s.value;n.set(a.input,a)}let i=[];for(let s of r){if(s.type==="input")i.push({...n.has(s.sequence)?{task:`input-${s.sequence}`}:{},action:structuredClone(s.value)});if(s.type==="completion"){let a=s.value;i.push({action:{type:"await",task:`input-${a.input}`,...a.error===void 0?{}:{error:a.error}}})}}let o={...t===void 0?{}:{seed:t},context:structuredClone(r.find((s)=>s.type==="context")?.value),steps:i};return yt(o),o}function Jn(e){return yt(e),JSON.stringify(hr(e))}function ns(e){let t=ht(JSON.parse(e));return yt(t),t}async function Kn(e,t){switch(t.type){case"initialize":await e.initialize(Object.hasOwn(t,"warmupBars")?{warmupBars:t.warmupBars}:{});return;case"start":await e.start();return;case"stop":await e.stop();return;case"restart":await e.restart();return;case"crashAndRestart":await e.crashAndRestart();return;case"setTime":e.setTime(t.datetime);return;case"advanceTime":e.advanceTime(t.milliseconds);return;case"market":e.pushMarketEvent(t.tick,t.closedBars??[]);return;case"bar":e.pushBar(t.value,{datetime:t.datetime});return;case"cancelOrder":e.cancelOrder(Le(t.vtOrderId,e));return;case"expectFault":e.expectFault(t.message);return;case"broker":{let r=e.broker[t.method];if(!Object.hasOwn(e.broker,t.method)||typeof r!=="function"||t.method==="snapshot"||t.method==="pendingReports")throw Error("Invalid broker action");await Reflect.apply(r,e.broker,Le(t.args,e));return}case"gateway":{let r=e.gateway[t.method];if(!Object.hasOwn(e.gateway,t.method)||typeof r!=="function"||t.method==="pendingRequests")throw Error("Invalid gateway action");await Reflect.apply(r,e.gateway,Le(t.args,e));return}default:throw Error(`Unknown scenario action: ${t.type}`)}}function Le(e,t){if(Array.isArray(e))return e.map((r)=>Le(r,t));if(e&&typeof e==="object"){let r=e;if(Object.keys(r).length===1&&Object.hasOwn(r,"submission")){let n=r.submission;if(!Number.isSafeInteger(n)||n<0)throw Error("Invalid submission reference");let i=t.submissions[n];if(!i)throw Error(`Submission reference does not exist: ${n}`);return i.vtOrderId}if(Object.keys(r).length===1&&typeof r.request==="string"){let n=t.gateway.pendingRequests().find((i)=>i.method===r.request);if(!n)throw Error(`Pending request reference does not exist: ${r.request}`);return n.id}return Object.fromEntries(Object.entries(r).map(([n,i])=>[n,Le(i,t)]))}return e}function yt(e){if(!e||typeof e!=="object"||!Array.isArray(e.steps))throw Error("Scenario steps must be an array");if(e.seed!==void 0&&!Number.isSafeInteger(e.seed))throw Error("Scenario seed must be a safe integer");if(e.context!==void 0){if(!e.context||typeof e.context!=="object")throw Error("Invalid scenario context");if(Y(e.context.fixture),!e.context.options||typeof e.context.options!=="object"||Array.isArray(e.context.options)||Object.hasOwn(e.context.options,"paperExecution"))throw Error("Invalid portable scenario options");if(e.context.customPaperExecution!==void 0&&e.context.customPaperExecution!==!0)throw Error("Invalid custom Paper hook marker")}let t=-1,r=new Set,n=new Set;for(let i of e.steps){if(!i||!i.action||typeof i.action.type!=="string")throw Error("Invalid scenario step");if(i.task!==void 0){if(!i.task||r.has(i.task)||i.action.type==="await")throw Error("Scenario task names must be unique");r.add(i.task)}if(i.action.type==="await"){if(!r.has(i.action.task)||n.has(i.action.task))throw Error(`Unknown or already joined task: ${i.action.task}`);n.add(i.action.task)}if(i.at!==void 0){if(!Number.isSafeInteger(i.at)||i.at<t||i.at<0)throw Error("Scenario times must be nonnegative and ordered");t=i.at}}if(r.size!==n.size)throw Error("Every scenario task must have an await step")}var G="$vibekTesting";function hr(e,t=new Set){if(e===void 0)return{[G]:"undefined"};if(Object.is(e,-0))return{[G]:"number",value:"-0"};if(typeof e==="number"&&!Number.isFinite(e))return{[G]:"number",value:String(e)};if(e===null||typeof e==="string"||typeof e==="boolean"||typeof e==="number")return e;if(typeof e!=="object")throw Error(`Scenario cannot serialize ${typeof e}`);if(t.has(e))throw Error("Scenario contains a cycle");t.add(e);try{if(Array.isArray(e))return e.map((n)=>hr(n,t));if(Object.getPrototypeOf(e)!==Object.prototype&&Object.getPrototypeOf(e)!==null)throw Error("Scenario values must be plain objects");let r=Object.entries(e).map(([n,i])=>[n,hr(i,t)]);return Object.hasOwn(e,G)?{[G]:"object",entries:r}:Object.fromEntries(r)}finally{t.delete(e)}}function ht(e){if(!e||typeof e!=="object")return e;if(Array.isArray(e))return e.map(ht);let t=e;if(!Object.hasOwn(t,G))return Object.fromEntries(Object.entries(t).map(([r,n])=>[r,ht(n)]));if(t[G]==="undefined")return;if(t[G]==="number"&&["NaN","Infinity","-Infinity","-0"].includes(String(t.value)))return Number(t.value);if(t[G]==="object"&&Array.isArray(t.entries))return Object.fromEntries(t.entries.map((r)=>{if(!Array.isArray(r)||r.length!==2||typeof r[0]!=="string")throw Error("Invalid scenario object entry");return[r[0],ht(r[1])]}));throw Error("Invalid encoded scenario value")}var ye={definition:"SDK-001 strategy definition",paper:"SDK-101 paper lifecycle",live:"SDK-102 fake-live lifecycle",persistence:"SDK-103 state persistence and restart",replay:"SDK-104 deterministic replay"};function is(e){let{afterEach:t}=wt("bun:test"),r=Y(e.fixture),n=new Set,i=0,o=(s={})=>{let a=new ie(e.strategy,r,s);return n.add(a),a};return t(async()=>{let s=[...n];n.clear(),i=0;let d=(await Promise.allSettled(s.map((c)=>c.dispose()))).flatMap((c)=>c.status==="rejected"?[c.reason]:[]);if(d.length)throw AggregateError(d,"Strategy test cleanup failed")}),os(e.strategy,r,o),{createRuntime:o,bar:(s)=>H(r,s,i++),tick:(s)=>De(r,s,i++)}}function os(e,t,r){let{describe:n,expect:i,test:o}=wt("bun:test");n("SDK contract",()=>{o(ye.definition,()=>{let s=Se(e,"inspect",t.setting);i(s.ctor).toBe(e.strategy)}),o(ye.paper,async()=>{await Qn(r({mode:"paper"}),t.seedPrice)}),o(ye.live,async()=>{await Qn(r({mode:"live"}),t.seedPrice)}),o(ye.persistence,async()=>{let s=r({mode:"paper"});await s.initialize(),await s.start(),s.pushTick({lastPrice:t.seedPrice}),s.pushBar({close:t.seedPrice}),await s.stop(),s.settleActiveOrders();let a=s.snapshot();await s.restart();let d=s.snapshot();i(d.pos).toBe(a.pos),i(d.variables).toEqual(a.variables),s.assertHealthy("\u91CD\u542F")}),o(ye.replay,async()=>{for(let s of["paper","live"]){let a=await pr(r({mode:s}),t,s),d=await pr(r({mode:s}),t,s);fr(a.trace,d.trace),i(a).toEqual(d)}})})}async function Qn(e,t){let{expect:r}=wt("bun:test");await e.initialize(),r(e.callbackCounts.onInit).toBe(1),e.assertHealthy("\u521D\u59CB\u5316"),await e.start(),r(e.callbackCounts.onStart).toBe(1);let n={...e.callbackCounts};e.pushTick({lastPrice:t}),e.pushBar({close:t}),r(e.callbackCounts.onTick-n.onTick).toBe(1),r(e.callbackCounts.onBar-n.onBar).toBe(1),e.assertHealthy("\u884C\u60C5\u56DE\u8C03"),e.settleActiveOrders(),await e.stop(),r(e.callbackCounts.onStop).toBe(1),e.settleActiveOrders(),r(e.snapshot()).toMatchObject({trading:!1,activeOrders:0,fault:null})}function Cu(e,t={}){return new ie(e.strategy,Y(e.fixture),t)}export{ft as StrategyScenarioError,ts as assertStrategyReplay,rs as captureStrategyScenario,Cu as createStrategyTest,ns as parseStrategyScenario,gr as runStrategyScenario,Jn as serializeStrategyScenario,is as setupStrategyTests};
74
+ ${Wn({expected:e[r],actual:t[r]},{depth:8})}`)}function ns(e,t){let r=e.trace,n=new Map;for(let s of r)if(s.type==="completion"){let a=s.value;n.set(a.input,a)}let i=[];for(let s of r){if(s.type==="input")i.push({...n.has(s.sequence)?{task:`input-${s.sequence}`}:{},action:structuredClone(s.value)});if(s.type==="completion"){let a=s.value;i.push({action:{type:"await",task:`input-${a.input}`,...a.error===void 0?{}:{error:a.error}}})}}let o={...t===void 0?{}:{seed:t},context:structuredClone(r.find((s)=>s.type==="context")?.value),steps:i};return yt(o),o}function Jn(e){return yt(e),JSON.stringify(hr(e))}function is(e){let t=ht(JSON.parse(e));return yt(t),t}async function Kn(e,t){switch(t.type){case"initialize":await e.initialize(Object.hasOwn(t,"warmupBars")?{warmupBars:t.warmupBars}:{});return;case"start":await e.start();return;case"stop":await e.stop();return;case"restart":await e.restart();return;case"crashAndRestart":await e.crashAndRestart();return;case"setTime":e.setTime(t.datetime);return;case"advanceTime":e.advanceTime(t.milliseconds);return;case"market":e.pushMarketEvent(t.tick,t.closedBars??[]);return;case"bar":e.pushBar(t.value,{datetime:t.datetime});return;case"cancelOrder":e.cancelOrder(Le(t.vtOrderId,e));return;case"expectFault":e.expectFault(t.message);return;case"broker":{let r=e.broker[t.method];if(!Object.hasOwn(e.broker,t.method)||typeof r!=="function"||t.method==="snapshot"||t.method==="pendingReports")throw Error("Invalid broker action");await Reflect.apply(r,e.broker,Le(t.args,e));return}case"gateway":{let r=e.gateway[t.method];if(!Object.hasOwn(e.gateway,t.method)||typeof r!=="function"||t.method==="pendingRequests")throw Error("Invalid gateway action");await Reflect.apply(r,e.gateway,Le(t.args,e));return}default:throw Error(`Unknown scenario action: ${t.type}`)}}function Le(e,t){if(Array.isArray(e))return e.map((r)=>Le(r,t));if(e&&typeof e==="object"){let r=e;if(Object.keys(r).length===1&&Object.hasOwn(r,"submission")){let n=r.submission;if(!Number.isSafeInteger(n)||n<0)throw Error("Invalid submission reference");let i=t.submissions[n];if(!i)throw Error(`Submission reference does not exist: ${n}`);return i.vtOrderId}if(Object.keys(r).length===1&&typeof r.request==="string"){let n=t.gateway.pendingRequests().find((i)=>i.method===r.request);if(!n)throw Error(`Pending request reference does not exist: ${r.request}`);return n.id}return Object.fromEntries(Object.entries(r).map(([n,i])=>[n,Le(i,t)]))}return e}function yt(e){if(!e||typeof e!=="object"||!Array.isArray(e.steps))throw Error("Scenario steps must be an array");if(e.seed!==void 0&&!Number.isSafeInteger(e.seed))throw Error("Scenario seed must be a safe integer");if(e.context!==void 0){if(!e.context||typeof e.context!=="object")throw Error("Invalid scenario context");if(Y(e.context.fixture),!e.context.options||typeof e.context.options!=="object"||Array.isArray(e.context.options)||Object.hasOwn(e.context.options,"paperExecution"))throw Error("Invalid portable scenario options");if(e.context.customPaperExecution!==void 0&&e.context.customPaperExecution!==!0)throw Error("Invalid custom Paper hook marker")}let t=-1,r=new Set,n=new Set;for(let i of e.steps){if(!i||!i.action||typeof i.action.type!=="string")throw Error("Invalid scenario step");if(i.task!==void 0){if(!i.task||r.has(i.task)||i.action.type==="await")throw Error("Scenario task names must be unique");r.add(i.task)}if(i.action.type==="await"){if(!r.has(i.action.task)||n.has(i.action.task))throw Error(`Unknown or already joined task: ${i.action.task}`);n.add(i.action.task)}if(i.at!==void 0){if(!Number.isSafeInteger(i.at)||i.at<t||i.at<0)throw Error("Scenario times must be nonnegative and ordered");t=i.at}}if(r.size!==n.size)throw Error("Every scenario task must have an await step")}var G="$vibekTesting";function hr(e,t=new Set){if(e===void 0)return{[G]:"undefined"};if(Object.is(e,-0))return{[G]:"number",value:"-0"};if(typeof e==="number"&&!Number.isFinite(e))return{[G]:"number",value:String(e)};if(e===null||typeof e==="string"||typeof e==="boolean"||typeof e==="number")return e;if(typeof e!=="object")throw Error(`Scenario cannot serialize ${typeof e}`);if(t.has(e))throw Error("Scenario contains a cycle");t.add(e);try{if(Array.isArray(e))return e.map((n)=>hr(n,t));if(Object.getPrototypeOf(e)!==Object.prototype&&Object.getPrototypeOf(e)!==null)throw Error("Scenario values must be plain objects");let r=Object.entries(e).map(([n,i])=>[n,hr(i,t)]);return Object.hasOwn(e,G)?{[G]:"object",entries:r}:Object.fromEntries(r)}finally{t.delete(e)}}function ht(e){if(!e||typeof e!=="object")return e;if(Array.isArray(e))return e.map(ht);let t=e;if(!Object.hasOwn(t,G))return Object.fromEntries(Object.entries(t).map(([r,n])=>[r,ht(n)]));if(t[G]==="undefined")return;if(t[G]==="number"&&["NaN","Infinity","-Infinity","-0"].includes(String(t.value)))return Number(t.value);if(t[G]==="object"&&Array.isArray(t.entries))return Object.fromEntries(t.entries.map((r)=>{if(!Array.isArray(r)||r.length!==2||typeof r[0]!=="string")throw Error("Invalid scenario object entry");return[r[0],ht(r[1])]}));throw Error("Invalid encoded scenario value")}var ye={definition:"SDK-001 strategy definition",paper:"SDK-101 paper lifecycle",live:"SDK-102 fake-live lifecycle",persistence:"SDK-103 state persistence and restart",replay:"SDK-104 deterministic replay"};function os(e){let{afterEach:t}=wt("bun:test"),r=Y(e.fixture),n=new Set,i=0,o=(s={})=>{let a=new ie(e.strategy,r,s);return n.add(a),a};return t(async()=>{let s=[...n];n.clear(),i=0;let d=(await Promise.allSettled(s.map((c)=>c.dispose()))).flatMap((c)=>c.status==="rejected"?[c.reason]:[]);if(d.length)throw AggregateError(d,"Strategy test cleanup failed")}),ss(e.strategy,r,o),{createRuntime:o,bar:(s)=>H(r,s,i++),tick:(s)=>De(r,s,i++)}}function ss(e,t,r){let{describe:n,expect:i,test:o}=wt("bun:test");n("SDK contract",()=>{o(ye.definition,()=>{let s=Se(e,"inspect",t.setting);i(s.ctor).toBe(e.strategy)}),o(ye.paper,async()=>{await Qn(r({mode:"paper"}),t.seedPrice)}),o(ye.live,async()=>{await Qn(r({mode:"live"}),t.seedPrice)}),o(ye.persistence,async()=>{let s=r({mode:"paper"});await s.initialize(),await s.start(),s.pushTick({lastPrice:t.seedPrice}),s.pushBar({close:t.seedPrice}),await s.stop(),s.settleActiveOrders();let a=s.snapshot();await s.restart();let d=s.snapshot();i(d.pos).toBe(a.pos),i(d.variables).toEqual(a.variables),s.assertHealthy("\u91CD\u542F")}),o(ye.replay,async()=>{for(let s of["paper","live"]){let a=await pr(r({mode:s}),t,s),d=await pr(r({mode:s}),t,s);fr(a.trace,d.trace),i(a).toEqual(d)}})})}async function Qn(e,t){let{expect:r}=wt("bun:test");await e.initialize(),r(e.callbackCounts.onInit).toBe(1),e.assertHealthy("\u521D\u59CB\u5316"),await e.start(),r(e.callbackCounts.onStart).toBe(1);let n={...e.callbackCounts};e.pushTick({lastPrice:t}),e.pushBar({close:t}),r(e.callbackCounts.onTick-n.onTick).toBe(1),r(e.callbackCounts.onBar-n.onBar).toBe(1),e.assertHealthy("\u884C\u60C5\u56DE\u8C03"),e.settleActiveOrders(),await e.stop(),r(e.callbackCounts.onStop).toBe(1),e.settleActiveOrders(),r(e.snapshot()).toMatchObject({trading:!1,activeOrders:0,fault:null})}function Pu(e,t={}){return new ie(e.strategy,Y(e.fixture),t)}export{ft as StrategyScenarioError,rs as assertStrategyReplay,ns as captureStrategyScenario,Pu as createStrategyTest,is as parseStrategyScenario,gr as runStrategyScenario,Jn as serializeStrategyScenario,os as setupStrategyTests};