官方API文档地址
TWS API v9.72+: Trader Workstation APIhttps://interactivebrokers.github.io/tws-api/一.如何获取ETH/EUR/USD/BTC等外汇或者数字货币实时数据走势
1.第一种方式我们可以通过
eg:m_s.reqRealTimeBars(1,contract,5,"MIDPOINT",true,Collections.emptyList());
我们可以通过5秒k线数据图请求5秒内快照数据进行拼接
注意该方法是在 realtimeBar中进行回调我们需要在此接口中重写相关方法处理业务逻辑
简单的贴一份代码:
建立TWS CLIENT连接:
private EJavaSignal m_signal = new EJavaSignal(); private EClientSocket m_s = new EClientSocket(this, m_signal); m_s.eConnect("localhost", 7496, 0); final EReader reader = new EReader(m_s, m_signal); reader.start(); new Thread(() -> { while (m_s.isConnected()) { m_signal.waitForSignal(); try { SwingUtilities.invokeAndWait(() -> { try { reader.processMsgs(); } catch (Exception e) { error(e); } }); } catch (Exception e) { error(e); } } }).start(); if (NextOrderId < 0) { sleep(1000); }
以EUR为例:
Contract contract = new Contract();
contract.symbol("EUR");
contract.secType("CASH");
contract.exchange("IDEALPRO");
contract.currency("USD");
m_s.reqMarketDataType(1);
m_s.reqRealTimeBars(1,contract,5,"MIDPOINT",true,Collections.emptyList());
处理回调方法:
@Override public void realtimeBar(int reqId, long time, double open, double high, double low, double close, Decimal volume, Decimal wap, int count) throws UnirestException { //下面代码实在回调中处理自己的相关业务 我们是通过http请求我们自己的接口发送相关数据 在通过webscoket进行数据的推送
Unirest.post(twsnotifyUrl) .header("Content-Type", "application/json") .header("charset","utf-8") .body(jsonObject.toJSONString()).asString(); }
2.第二种方式我们可以通过
m_s.reqMktData(9,contract9,"",false,false, Collections.emptyList());
每秒快照的方式进行数据的请求只不过该方法我们回调的接口是不同的这点需要注意下
tickPrice我们可以通过这个回调接口得到k线所需要的相关价格进行k线数据的构造
话不多说直接贴代码 建立连接的过程是相同的
@Override public void tickPrice(int tickerId, int field, double price, TickAttrib attribs) throws UnirestException { //处理相关业务 }
二.盈透数据的坑
因为我们是通过TWS客户端获取的实时数据推送 所以这一点也是比较坑的 我们需要VPS 取部署windows服务器 安装TWS客户端进行数据的推送 但是TWS客户端由于他的维护缺点每天都会定时的进行关闭维护 所以我们要向获取实时走势 就需要定时的维护TWS客户端 但是作为一个程序员 我们也是为了各种苦逼的事情想到的解决办法就是 进程守护
直接上代码 让TWS每天定时守护进程 让他关机自己启动
@echo off
set _task=tws.exe
set _svr=c:\windows\tws.exe
set _des=start.bat
set _interval=50
:checkstart
for /f "tokens=5" %%n in ('qprocess.exe ^| find "%_task%" ') do (
if %%n==%_task% (goto checkag) else goto startsvr
)
:startsvr
echo %time%
echo ********program start begin********
echo program reboost at %time% ,please check log. >> restart_service.txt
start %_svr%
::echo exit >> %_des%
::start %_des%
::set/p=.<nul
::for /L %%i in (1 1 10) do set /p a=.<nul&ping.exe /n 2 127.0.0.1>nul
::echo .
::echo Wscript.Sleep WScript.Arguments(0) >%tmp%\delay.vbs
::cscript //b //nologo %tmp%\delay.vbs 10000
::del %_des% /Q
echo ********program start finished ********
goto checkstart
:checkag
echo %time% program %_task% run normally, next check will be lauched in %_interval% milliseconds ...
echo Wscript.Sleep WScript.Arguments(0) >%tmp%\delay.vbs
cscript //b //nologo %tmp%\delay.vbs %_interval%
goto checkstart
当然了除了脚本 也给大家推荐个软件 Always Open 如果有需要自行下载
三.webscoket数据推送
public class AliyunClient extends WebSocketClient { protected Logger logger = LoggerFactory.getLogger(this.getClass()); private final AliyunExchangeService aliyunExchangeService; private AliyunMonitor aliyunMonitor; public AliyunClient(URI serverUri, AliyunExchangeService aliyunExchangeService) { super(serverUri,new Draft_6455()); this.aliyunExchangeService = aliyunExchangeService; } @Override public void onOpen(ServerHandshake handshakedata) { logger.info("AliyunClient onOpen {} {}", handshakedata.getHttpStatusMessage(), handshakedata.getHttpStatus()); aliyunMonitor = new AliyunMonitor(); ScheduledExecutorService executorService = new ScheduledThreadPoolExecutor(1); executorService.scheduleAtFixedRate(aliyunMonitor, 0, 10, TimeUnit.SECONDS); aliyunExchangeService.init(); } @Override public void onMessage(String message) { logger.info("AliyunClient message: {} ", message); if (message.contains("ping")){ aliyunMonitor = new AliyunMonitor(); return; } if (message.contains("rm")) { aliyunExchangeService.handleData(message); } } @Override public void onMessage(ByteBuffer byteBuffer) { } @Override public void onClose(int code, String reason, boolean remote) { logger.error("AliyunClient onClose code: {} message: {}", code, reason); aliyunExchangeService.stop(); } @Override public void onError(Exception ex) { logger.error("AliyunClient error"); } class AliyunMonitor implements Runnable { @Override public void run() { sendPing(); } private void sendPing() { send("/heartbeat/ok"); } } }
@Component public class AliyunExchangeService implements IExchangeService { protected Logger logger = LoggerFactory.getLogger(this.getClass()); // private static final String WEBSOCKET_URL = WebSocketProperties.ALIYUN_URL + WebSocketProperties.TOKEN; private final Map<String, String> TRADE_DETAIL_MAP = new HashMap<>(); private AliyunClient aliyunClient; @Resource private MergeService mergeService; @Resource private SymbolCache symbolCache; @Override public void start() { try { TRADE_DETAIL_MAP.clear(); logger.info("启动AliyunClient"); // aliyunClient = new AliyunClient(new URI(WEBSOCKET_URL), this); // aliyunClient.connect(); } catch (Exception e) { logger.error(e.getMessage(), e); } } @Override public void stop() { //重连 if (aliyunClient.getReadyState() == WebSocket.READYSTATE.OPEN || aliyunClient.getReadyState() == WebSocket.READYSTATE.CONNECTING) { aliyunClient.close(); } aliyunClient = null; try { Thread.sleep(2000); } catch (InterruptedException e) { logger.error(e.getMessage(), e); } start(); } public void init() { List<String> exchangeSymbolList = symbolCache.listExchangeSymbol(MarketConstant.EXCHANGE_ALIYUN); for (String symbol : exchangeSymbolList) { //订阅缓存中的所有行情数据 sub(symbol); } } @Override public void sub(String symbol) { subTradeMarKet(symbol); } @Override public void unsub(String symbol) { unsubTradeMarket(symbol); } /** * 订阅行情数据 * @param symbol */ private void subTradeMarKet(String symbol) { String sub = "/sub/" + symbol; if (TRADE_DETAIL_MAP.containsKey(symbol)) { return; } TRADE_DETAIL_MAP.put(symbol, sub); aliyunClient.send(sub); } /** * 退订行情数据 */ private void unsubTradeMarket(String symbol) { String sub = "/unsub/" + symbol; if (!TRADE_DETAIL_MAP.containsKey(symbol)) { return; } TRADE_DETAIL_MAP.remove(symbol); aliyunClient.send(sub); } public void handleData(String message) { try { 数据处理 //} } catch (Exception e) { logger.error(e.getMessage(), e); } } }
public interface IExchangeService { void start(); void stop(); void sub(String symbol); void unsub(String symbol); }