TWS 是世界著名的盈透证券的交易平台,可以交易全球股票、期货、外汇等金融产品。而盈透证券的老板,又是一个以量化交易起家的传奇人物,因此在盈透很早的时候,就提供了基于TWS的API,供全世界的玩家开发出自己的交易系统。 因为个人兴趣爱好的原因,所以一直想开发一款属于自己的交易软件,后来注意到这个产品后,决定自己也试一试。 想要使用TWS,需要先去册盈透证券的官网注册投资者账号,并且在账号开通后三个月内向你的投资人账号打款以激活账号,否则注册了账号而不打款,三个月后账户就会被注销掉,也意味着你不能使用TWS进行下一步的开发了。 注册了账户、打入资金后,就可以在盈透证券的官网下载TWS交易客户端,同时还有IB API。IB API目前提供有Linux,Windows,MacOS三个系统的版本,根据你自己擅长的系统和语言,选择对应的API进行下载就行。这里笔者选择的是Windows,因为之后考虑做UI的时候,C#.NET 会十分方便。当然,笔者本人会Java,Python等语言技术,而且IB API的使用方法基本一致,所以也就无所谓语言的优劣,只要方便使用就好。 通信前准备使用Windows编程,需要准备的是Visual Studio或者支持相关语言的开发工具和IDE,因为笔者用C#做这个项目,所以选择了Visual Studio。另一方面,因为Windows系统的限制,需要提前准备好程序的通信端口,并在防火墙、杀毒软件设置为打开。 通信前还需要做最后一个操作,打开TWS,并在全局设置中将允许连接打开,如果你只允许本地连接,那么点击“Allow connection from localhost only”就行,推荐这样做,因为比较安全。 开始编程打开Visual studio并新建一个C#的工程,同时在工程“Solution Explorer”位置,找到工程的“References”,并添加IB API的DLL链接库。 IB API的库文件,存储于你安装的位置,只要找一找就能很容易找到。 工程目前包含两个主要文件,一个是Program.cs和TWSDeliverInterfaceImp.cs。 TWSDeliverInterfaceImp,是对EWrapper类的实现,这个是非常重要的一个类,包含了对所有事件的处理和响应,不过当前我们并不需要做太多的事件处理,因此可以把所有需要实现的方法空置即可。 - using IBApi;
- using System;
- using System.Collections.Generic;
- namespace AbsZeroTWS
- {
- class TWSDeliverInterfaceImp : EWrapper
- {
- private EClientSocket clientSocket;
- private int nextOrderId;
- private int clientId;
- public TWSDeliverInterfaceImp(EReaderSignal signal)
- {
- clientSocket = new EClientSocket(this, signal);
- }
- public int ClientId
- {
- get { return clientId; }
- set { clientId = value; }
- }
- public EClientSocket ClientSocket
- {
- get { return clientSocket; }
- set { clientSocket = value; }
- }
- public int NextOrderId
- {
- get { return nextOrderId; }
- set { nextOrderId = value; }
- }
- public void accountDownloadEnd(string account) { }
- public void accountSummary(int reqId, string account, string tag, string value, string currency) { }
- public void accountSummaryEnd(int reqId) { }
- public void accountUpdateMulti(int requestId, string account, string modelCode, string key, string value, string currency) { }
- public void accountUpdateMultiEnd(int requestId) { }
- public void bondContractDetails(int reqId, ContractDetails contract) { }
- public void commissionReport(CommissionReport commissionReport) { }
- public void connectAck() { }
- public void connectionClosed() { }
- public void contractDetails(int reqId, ContractDetails contractDetails) { }
- public void contractDetailsEnd(int reqId) { }
- public void currentTime(long time) { }
- public void deltaNeutralValidation(int reqId, UnderComp underComp) { }
- public void displayGroupList(int reqId, string groups) { }
- public void displayGroupUpdated(int reqId, string contractInfo) { }
- public void error(string str) { }
- public void error(Exception e) { }
- public void error(int id, int errorCode, string errorMsg) { }
- public void execDetails(int reqId, Contract contract, Execution execution) { }
- public void execDetailsEnd(int reqId) { }
- public void fundamentalData(int reqId, string data) { }
- public void historicalData(int reqId, string date, double open, double high, double low, double close, int volume, int count, double WAP, bool hasGaps) { }
- public void historicalDataEnd(int reqId, string start, string end) { }
- public void managedAccounts(string accountsList) { }
- public void marketDataType(int reqId, int marketDataType) { }
- public void nextValidId(int orderId) { }
- public void openOrder(int orderId, Contract contract, Order order, OrderState orderState) { }
- public void openOrderEnd() { }
- public void orderStatus(int orderId, string status, double filled, double remaining, double avgFillPrice, int permId, int parentId, double lastFillPrice, int clientId, string whyHeld) { }
- public void position(string account, Contract contract, double pos, double avgCost) { }
- public void positionEnd() { }
- public void positionMulti(int requestId, string account, string modelCode, Contract contract, double pos, double avgCost) { }
- public void positionMultiEnd(int requestId) { }
- public void realtimeBar(int reqId, long time, double open, double high, double low, double close, long volume, double WAP, int count) { }
- public void receiveFA(int faDataType, string faXmlData) { }
- public void scannerData(int reqId, int rank, ContractDetails contractDetails, string distance, string benchmark, string projection, string legsStr) { }
- public void scannerDataEnd(int reqId) { }
- public void scannerParameters(string xml) { }
- public void securityDefinitionOptionParameter(int reqId, string exchange, int underlyingConId, string tradingClass, string multiplier, HashSet<string> expirations, HashSet<double> strikes) { }
- public void securityDefinitionOptionParameterEnd(int reqId) { }
- public void softDollarTiers(int reqId, SoftDollarTier[] tiers) { }
- public void tickEFP(int tickerId, int tickType, double basisPoints, string formattedBasisPoints, double impliedFuture, int holdDays, string futureLastTradeDate, double dividendImpact, double dividendsToLastTradeDate) { }
- public void tickGeneric(int tickerId, int field, double value) { }
- public void tickOptionComputation(int tickerId, int field, double impliedVolatility, double delta, double optPrice, double pvDividend, double gamma, double vega, double theta, double undPrice) { }
- public void tickPrice(int tickerId, int field, double price, int canAutoExecute) { }
- public void tickSize(int tickerId, int field, int size) { }
- public void tickSnapshotEnd(int tickerId) { }
- public void tickString(int tickerId, int field, string value) { }
- public void updateAccountTime(string timestamp) { }
- public void updateAccountValue(string key, string value, string currency, string accountName) { }
- public void updateMktDepth(int tickerId, int position, int operation, int side, double price, int size) { }
- public void updateMktDepthL2(int tickerId, int position, string marketMaker, int operation, int side, double price, int size) { }
- public void updateNewsBulletin(int msgId, int msgType, string message, string origExchange) { }
- public void updatePortfolio(Contract contract, double position, double marketPrice, double marketValue, double averageCost, double unrealisedPNL, double realisedPNL, string accountName) { }
- public void verifyAndAuthCompleted(bool isSuccessful, string errorText) { }
- public void verifyAndAuthMessageAPI(string apiData, string xyzChallenge) { }
- public void verifyCompleted(bool isSuccessful, string errorText) { }
- public void verifyMessageAPI(string apiData) { }
- }
- }
复制代码
令一个类是主类,我们实现以下代码。 - using IBApi;
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- using System.Threading;
- using System.Threading.Tasks;
- namespace AbsZeroTWS
- {
- class Program
- {
- static void Main(string[] args)
- {
- EReaderMonitorSignal signal = new EReaderMonitorSignal();
- TWSDeliverInterfaceImp tws = new TWSDeliverInterfaceImp(signal);
- tws.ClientSocket.eConnect("localhost", 7000, 0);
- var reader = new EReader(tws.ClientSocket, signal);
- reader.Start();
- if (tws.ClientSocket.IsConnected())
- {
- Console.WriteLine("Connection is established!");
- }
- /*
- new Thread(() => {
- while (tws.ClientSocket.IsConnected())
- {
- signal.waitForSignal();
- reader.processMsgs();
- }
- }) { IsBackground = true }.Start();
- */
- Console.ReadKey();
- }
- }
- }
复制代码
点击运行后,程序就能跟TWS进行连接,并打印出connection is established. |