futu-sdk
Version:
futu-api 的高性能精简易用版;基于*.proto静态编译,提供高性能的多层封装但层层开放的易用接口,获取最原始最完整的量化数据;相较于Python, nodejs更接近Web, 从而轻而易举搭建一个可视化交易站点,这是进行可控量化交易的不二选择。
2 lines (1 loc) • 12.5 kB
JavaScript
import S from"crypto";import I from"ws";function*Q(c){let t={},e=[],s=c(i=>{e[0]&&!(e[0]instanceof Promise)?e.shift().resolve(i):e.push(Promise.resolve(i))},i=>{t.reason=i,t.rejected=!0;for(let n of e)n instanceof Promise||n.reject(i)});try{for(;;)yield s.then(()=>{if(e[0]instanceof Promise)return e.shift();if(t.rejected)throw t.reason;return new Promise((i,n)=>{e.push({resolve:i,reject:n})})})}finally{s.then(i=>i())}}var h="ft-v1.0",T=1,R=(c,t)=>{let e=T++,s=Buffer.alloc(20+t.byteLength),i=s.write(h,0,"utf8");for(;i<8;)i=s.writeUint8(0,i);return i=s.writeUint32BE(c,i),i=s.writeBigUint64BE(BigInt(e),i),s.set(t,i),{message:s.buffer,session:e}},_=c=>{let t=Buffer.from(c),e=Number(t.readBigUint64BE(12)),s=t.readInt32BE(20),i=t.toString("utf8",24,44).replace(/\0/g,""),n=new Uint8Array(t.subarray(44));return new Uint8Array(t.subarray(44)),{session:e,message:{errorCode:s,errorMessage:i,protobuf:n}}};import*as o from"futu-sdk/proto";var r={InitWebSocket:{cmd:1,name:o.InitWebSocket,description:"\u521D\u59CB\u5316\u8FDE\u63A5"},GetGlobalState:{cmd:1002,name:o.GetGlobalState,description:"\u83B7\u53D6\u5168\u5C40\u72B6\u6001"},KeepAlive:{cmd:1004,name:o.KeepAlive,description:"\u5FC3\u8DF3"},GetUserInfo:{cmd:1005,name:o.GetUserInfo,description:"\u83B7\u53D6\u7528\u6237\u4FE1\u606F"},GetDelayStatistics:{cmd:1007,name:o.GetDelayStatistics,description:"\u83B7\u53D6\u5EF6\u8FDF\u7EDF\u8BA1"},QotSub:{cmd:3001,name:o.Qot_Sub,description:"\u8BA2\u9605\u6216\u8005\u53CD\u8BA2\u9605"},QotRegQotPush:{cmd:3002,name:o.Qot_RegQotPush,description:"\u6CE8\u518C\u63A8\u9001"},QotGetSubInfo:{cmd:3003,name:o.Qot_GetSubInfo,description:"\u83B7\u53D6\u8BA2\u9605\u4FE1\u606F"},QotGetBasicQot:{cmd:3004,name:o.Qot_GetBasicQot,description:"\u83B7\u53D6\u57FA\u672C\u884C\u60C5"},QotGetKL:{cmd:3006,name:o.Qot_GetKL,description:"\u83B7\u53D6K\u7EBF"},QotGetRT:{cmd:3008,name:o.Qot_GetRT,description:"\u83B7\u53D6\u5206\u65F6"},QotGetTicker:{cmd:3010,name:o.Qot_GetTicker,description:"\u83B7\u53D6\u9010\u7B14"},QotGetOrderBook:{cmd:3012,name:o.Qot_GetOrderBook,description:"\u83B7\u53D6\u4E70\u5356\u76D8"},QotGetBroker:{cmd:3014,name:o.Qot_GetBroker,description:"\u83B7\u53D6\u7ECF\u7EAA\u961F\u5217"},QotGetHistoryKL:{cmd:3100,name:o.Qot_GetHistoryKL,description:"\u83B7\u53D6\u5386\u53F2K\u7EBF"},QotGetHistoryKLPoints:{cmd:3101,name:o.Qot_GetHistoryKLPoints,description:"\u83B7\u53D6\u591A\u53EA\u80A1\u7968\u5386\u53F2\u5355\u70B9K\u7EBF"},QotGetRehab:{cmd:3102,name:o.Qot_GetRehab,description:"\u83B7\u53D6\u590D\u6743\u4FE1\u606F"},QotRequestHistoryKL:{cmd:3103,name:o.Qot_RequestHistoryKL,description:"\u62C9\u53D6\u5386\u53F2K\u7EBF\uFF0C\u4E0D\u8BFB\u672C\u5730\u5386\u53F2\u6570\u636EDB"},QotRequestHistoryKLQuota:{cmd:3104,name:o.Qot_RequestHistoryKLQuota,description:"\u62C9\u53D6\u5386\u53F2K\u7EBF\u5DF2\u7ECF\u7528\u6389\u7684\u989D\u5EA6"},QotRequestRehab:{cmd:3105,name:o.Qot_RequestRehab,description:"\u62C9\u53D6\u590D\u6743\u4FE1\u606F\uFF0C\u4E0D\u8BFB\u672C\u5730\u5386\u53F2\u6570\u636EDB"},QotGetSuspend:{cmd:3201,name:o.Qot_GetSuspend,description:"\u83B7\u53D6\u80A1\u7968\u505C\u724C\u4FE1\u606F"},QotGetStaticInfo:{cmd:3202,name:o.Qot_GetStaticInfo,description:"\u83B7\u53D6\u80A1\u7968\u9759\u6001\u4FE1\u606F"},QotGetSecuritySnapshot:{cmd:3203,name:o.Qot_GetSecuritySnapshot,description:"\u83B7\u53D6\u80A1\u7968\u5FEB\u7167"},QotGetPlateSet:{cmd:3204,name:o.Qot_GetPlateSet,description:"\u83B7\u53D6\u677F\u5757\u96C6\u5408\u4E0B\u7684\u677F\u5757"},QotGetPlateSecurity:{cmd:3205,name:o.Qot_GetPlateSecurity,description:"\u83B7\u53D6\u677F\u5757\u4E0B\u7684\u80A1\u7968"},QotGetReference:{cmd:3206,name:o.Qot_GetReference,description:"\u83B7\u53D6\u6B63\u80A1\u76F8\u5173\u80A1\u7968\uFF0C\u6682\u65F6\u53EA\u6709\u7A9D\u8F6E"},QotGetOwnerPlate:{cmd:3207,name:o.Qot_GetOwnerPlate,description:"\u83B7\u53D6\u80A1\u7968\u6240\u5C5E\u677F\u5757"},QotGetHoldingChangeList:{cmd:3208,name:o.Qot_GetHoldingChangeList,description:"\u83B7\u53D6\u5927\u80A1\u4E1C\u6301\u80A1\u53D8\u5316\u5217\u8868"},QotGetOptionChain:{cmd:3209,name:o.Qot_GetOptionChain,description:"\u83B7\u53D6\u671F\u6743\u94FE"},QotGetWarrant:{cmd:3210,name:o.Qot_GetWarrant,description:"\u83B7\u53D6\u6DA1\u8F6E"},QotGetCapitalFlow:{cmd:3211,name:o.Qot_GetCapitalFlow,description:"\u83B7\u53D6\u8D44\u91D1\u6D41\u5411"},QotGetCapitalDistribution:{cmd:3212,name:o.Qot_GetCapitalDistribution,description:"\u83B7\u53D6\u8D44\u91D1\u5206\u5E03"},QotGetUserSecurity:{cmd:3213,name:o.Qot_GetUserSecurity,description:"\u83B7\u53D6\u81EA\u9009\u80A1\u5206\u7EC4\u4E0B\u7684\u80A1\u7968"},QotModifyUserSecurity:{cmd:3214,name:o.Qot_ModifyUserSecurity,description:"\u4FEE\u6539\u81EA\u9009\u80A1\u5206\u7EC4\u4E0B\u7684\u80A1\u7968"},QotStockFilter:{cmd:3215,name:o.Qot_StockFilter,description:"\u6761\u4EF6\u9009\u80A1"},QotGetCodeChange:{cmd:3216,name:o.Qot_GetCodeChange,description:"\u83B7\u53D6\u80A1\u7968\u4EE3\u7801\u53D8\u5316\u4FE1\u606F"},QotGetIpoList:{cmd:3217,name:o.Qot_GetIpoList,description:"\u83B7\u53D6\u65B0\u80A1IPO"},QotGetFutureInfo:{cmd:3218,name:o.Qot_GetFutureInfo,description:"\u83B7\u53D6\u671F\u8D27\u5408\u7EA6\u8D44\u6599"},QotRequestTradeDate:{cmd:3219,name:o.Qot_RequestTradeDate,description:"\u83B7\u53D6\u5E02\u573A\u4EA4\u6613\u65E5"},QotSetPriceReminder:{cmd:3220,name:o.Qot_SetPriceReminder,description:"\u8BBE\u7F6E\u5230\u4EF7\u63D0\u9192"},QotGetPriceReminder:{cmd:3221,name:o.Qot_GetPriceReminder,description:"\u83B7\u53D6\u5230\u4EF7\u63D0\u9192"},QotGetUserSecurityGroup:{cmd:3222,name:o.Qot_GetUserSecurityGroup,description:"\u83B7\u53D6\u81EA\u9009\u80A1\u5206\u7EC4\u5217\u8868"},QotGetMarketState:{cmd:3223,name:o.Qot_GetMarketState,description:"\u83B7\u53D6\u80A1\u7968\u5BF9\u5E94\u5E02\u573A\u72B6\u6001"},QotGetOptionExpirationDate:{cmd:3224,name:o.Qot_GetOptionExpirationDate,description:"\u83B7\u53D6\u671F\u6743\u94FE\u5230\u671F\u65E5"},TrdGetAccList:{cmd:2001,name:o.Trd_GetAccList,description:"\u83B7\u53D6\u4EA4\u6613\u8D26\u6237\u5217\u8868"},TrdUnlockTrade:{cmd:2005,name:o.Trd_UnlockTrade,description:"\u89E3\u9501\u6216\u9501\u5B9A\u4EA4\u6613"},TrdSubAccPush:{cmd:2008,name:o.Trd_SubAccPush,description:"\u8BA2\u9605\u63A5\u6536\u63A8\u9001\u6570\u636E\u7684\u4EA4\u6613\u8D26\u6237"},TrdGetFunds:{cmd:2101,name:o.Trd_GetFunds,description:"\u83B7\u53D6\u8D26\u6237\u8D44\u91D1"},TrdGetPositionList:{cmd:2102,name:o.Trd_GetPositionList,description:"\u83B7\u53D6\u8D26\u6237\u6301\u4ED3"},TrdGetMaxTrdQtys:{cmd:2111,name:o.Trd_GetMaxTrdQtys,description:"\u83B7\u53D6\u6700\u5927\u4EA4\u6613\u6570\u91CF"},TrdGetOrderList:{cmd:2201,name:o.Trd_GetOrderList,description:"\u83B7\u53D6\u8BA2\u5355\u5217\u8868"},TrdPlaceOrder:{cmd:2202,name:o.Trd_PlaceOrder,description:"\u4E0B\u5355"},TrdModifyOrder:{cmd:2205,name:o.Trd_ModifyOrder,description:"\u4FEE\u6539\u8BA2\u5355"},TrdGetOrderFillList:{cmd:2211,name:o.Trd_GetOrderFillList,description:"\u83B7\u53D6\u6210\u4EA4\u5217\u8868"},TrdGetHistoryOrderList:{cmd:2221,name:o.Trd_GetHistoryOrderList,description:"\u83B7\u53D6\u5386\u53F2\u8BA2\u5355\u5217\u8868"},TrdGetHistoryOrderFillList:{cmd:2222,name:o.Trd_GetHistoryOrderFillList,description:"\u83B7\u53D6\u5386\u53F2\u6210\u4EA4\u5217\u8868"},TrdGetMarginRatio:{cmd:2223,name:o.Trd_GetMarginRatio,description:"\u83B7\u53D6\u878D\u8D44\u878D\u5238\u6570\u636E"},TrdGetOrderFee:{cmd:2225,name:o.Trd_GetOrderFee,description:"\u83B7\u53D6\u8BA2\u5355\u6536\u8D39\u660E\u7EC6\u6570\u636E"}};var q=({protobuf:c,errorCode:t,errorMessage:e},s)=>{if(t)throw new Error(`errorCode: ${t}, errorMessage: ${e}`);let{s2c:i,retMsg:n,retType:p}=s(c);if(p)throw new Error(`retType: ${p}, retMsg: ${n}`);return i},m=class{request;subscribe;constructor(t){this.request=({name:e,cmd:s,description:i},n,p=5e3)=>new Promise(async(a,u)=>{let d=e.Request.encode(e.Request.create(n)).finish(),G=(await t)(s,d,y=>{try{a(q(y,e.Response.decode))}catch({message:P}){u(new Error(`${i}, ${P}`))}finally{clearTimeout(l),G()}}),l=setTimeout(()=>{u(new Error(`${i} timeout`)),G()},p)}),this.subscribe=({name:e,cmd:s,description:i},n)=>Q(async(p,a)=>{let u=e.Request.encode(e.Request.create(n)).finish();return(await t)(s,u,d=>{try{p(q(d,e.Response.decode))}catch({message:G}){a(new Error(`${i}, ${G}`))}})})}InitWebSocket=(t,e=5e3)=>this.request(r.InitWebSocket,{c2s:t},e);Sub=t=>this.subscribe(r.QotSub,{c2s:t});GetAccList=(t,e=5e3)=>this.request(r.TrdGetAccList,{c2s:t},e);UnlockTrade=(t,e=5e3)=>this.request(r.TrdUnlockTrade,{c2s:t},e);SubAccPush=t=>this.subscribe(r.TrdSubAccPush,{c2s:t});GetFunds=(t,e=5e3)=>this.request(r.TrdGetFunds,{c2s:t},e);GetPositionList=(t,e=5e3)=>this.request(r.TrdGetPositionList,{c2s:t},e);GetMaxTrdQtys=(t,e=5e3)=>this.request(r.TrdGetMaxTrdQtys,{c2s:t},e);GetOrderList=(t,e=5e3)=>this.request(r.TrdGetOrderList,{c2s:t},e);PlaceOrder=(t,e=5e3)=>this.request(r.TrdPlaceOrder,{c2s:t},e);ModifyOrder=(t,e=5e3)=>this.request(r.TrdModifyOrder,{c2s:t},e);GetOrderFillList=(t,e=5e3)=>this.request(r.TrdGetOrderFillList,{c2s:t},e);GetHistoryOrderList=(t,e=5e3)=>this.request(r.TrdGetHistoryOrderList,{c2s:t},e);GetHistoryOrderFillList=(t,e=5e3)=>this.request(r.TrdGetHistoryOrderFillList,{c2s:t},e);GetMarginRatio=(t,e=5e3)=>this.request(r.TrdGetMarginRatio,{c2s:t},e);GetOrderFee=(t,e=5e3)=>this.request(r.TrdGetOrderFee,{c2s:t},e);GetGlobalState=(t,e=5e3)=>this.request(r.GetGlobalState,{c2s:t},e);RegQotPush=(t,e=5e3)=>this.request(r.QotRegQotPush,{c2s:t},e);GetSubInfo=(t,e=5e3)=>this.request(r.QotGetSubInfo,{c2s:t},e);GetTicker=(t,e=5e3)=>this.request(r.QotGetTicker,{c2s:t},e);GetBasicQot=(t,e=5e3)=>this.request(r.QotGetBasicQot,{c2s:t},e);GetOrderBook=(t,e=5e3)=>this.request(r.QotGetOrderBook,{c2s:t},e);GetKL=(t,e=5e3)=>this.request(r.QotGetKL,{c2s:t},e);GetRT=(t,e=5e3)=>this.request(r.QotGetRT,{c2s:t},e);GetBroker=(t,e=5e3)=>this.request(r.QotGetBroker,{c2s:t},e);RequestRehab=(t,e=5e3)=>this.request(r.QotRequestRehab,{c2s:t},e);RequestHistoryKL=(t,e=5e3)=>this.request(r.QotRequestHistoryKL,{c2s:t},e);RequestHistoryKLQuota=(t,e=5e3)=>this.request(r.QotRequestHistoryKLQuota,{c2s:t},e);GetStaticInfo=(t,e=5e3)=>this.request(r.QotGetStaticInfo,{c2s:t},e);GetSecuritySnapshot=(t,e=5e3)=>this.request(r.QotGetSecuritySnapshot,{c2s:t},e);GetPlateSet=(t,e=5e3)=>this.request(r.QotGetPlateSet,{c2s:t},e);GetPlateSecurity=(t,e=5e3)=>this.request(r.QotGetPlateSecurity,{c2s:t},e);GetReference=(t,e=5e3)=>this.request(r.QotGetReference,{c2s:t},e);GetOwnerPlate=(t,e=5e3)=>this.request(r.QotGetOwnerPlate,{c2s:t},e);GetHoldingChangeList=(t,e=5e3)=>this.request(r.QotGetHoldingChangeList,{c2s:t},e);GetOptionChain=(t,e=5e3)=>this.request(r.QotGetOptionChain,{c2s:t},e);GetWarrant=(t,e=5e3)=>this.request(r.QotGetWarrant,{c2s:t},e);GetCapitalFlow=(t,e=5e3)=>this.request(r.QotGetCapitalFlow,{c2s:t},e);GetCapitalDistribution=(t,e=5e3)=>this.request(r.QotGetCapitalDistribution,{c2s:t},e);GetUserSecurity=(t,e=5e3)=>this.request(r.QotGetUserSecurity,{c2s:t},e);ModifyUserSecurity=(t,e=5e3)=>this.request(r.QotModifyUserSecurity,{c2s:t},e);StockFilter=(t,e=5e3)=>this.request(r.QotStockFilter,{c2s:t},e);GetCodeChange=(t,e=5e3)=>this.request(r.QotGetCodeChange,{c2s:t},e);GetIpoList=(t,e=5e3)=>this.request(r.QotGetIpoList,{c2s:t},e);GetFutureInfo=(t,e=5e3)=>this.request(r.QotGetFutureInfo,{c2s:t},e);RequestTradeDate=(t,e=5e3)=>this.request(r.QotRequestTradeDate,{c2s:t},e);SetPriceReminder=(t,e=5e3)=>this.request(r.QotSetPriceReminder,{c2s:t},e);GetPriceReminder=(t,e=5e3)=>this.request(r.QotGetPriceReminder,{c2s:t},e);GetUserSecurityGroup=(t,e=5e3)=>this.request(r.QotGetUserSecurityGroup,{c2s:t},e);GetMarketState=(t,e=5e3)=>this.request(r.QotGetMarketState,{c2s:t},e);GetOptionExpirationDate=(t,e=5e3)=>this.request(r.QotGetOptionExpirationDate,{c2s:t},e)};var f=(c,t)=>{let e=new Map,s=new I(c);s.binaryType="arraybuffer";let i=(p,a,u)=>{let{session:d,message:G}=R(p,a);if(s.readyState!==I.OPEN)throw new Error("WebSocket closed");return s.send(G),e.set(d,u),()=>{e.delete(d)}},n=new Promise((p,a)=>{s.addEventListener("open",()=>{new m(Promise.resolve(i)).InitWebSocket({websocketKey:t?S.createHash("md5").update(t).digest("hex"):"",programmingLanguage:"JavaScript"}).then(()=>p(i)).catch(a)}),s.addEventListener("message",u=>{let{session:d,message:G}=_(u.data);e.get(d)?.(G)}),s.addEventListener("close",u=>{s.removeAllListeners("message"),s.removeAllListeners("close"),s.removeAllListeners("open"),a(u)})});return{webSocket:s,webRequest:new m(n)}},K=({host:c="127.0.0.1",port:t=33333,key:e})=>{let{webRequest:s}=f(`ws://${c}:${t}`,e);return s};export{f as getFutuApi,K as getWebRequest};