我刚刚开始使用Java上的IBKR API。我遵循API示例代码,特别是期权链示例,来了解如何获得特定股票的期权链。
这个例子很好地解决了这个问题,但我有一个问题——一旦加载了所有数据,我怎么知道?似乎没有办法说出来。示例代码能够判断何时加载了每一行,但似乎没有办法判断何时成功加载了ALL strike。
我原以为使用tickSnapshotEnd()
是有益的,但它似乎并不像我预期的那样工作。我希望每个完成的请求都会调用它一次。例如,如果我在2022/03/18到期日查询SOFI这样的股票,我会发现有35次罢工,但tickSnapshotEnd()
被调用了40+次,有些罢工重复了不止一次。
请注意,我正在请求快照数据,而不是实时/流式数据
reqOptionsMktData显然是您正在使用的示例代码中的一个方法。不确定您使用的是什么特定代码,所以这是一个一般性的响应。
首先你是正确的,没有办法通过API来判断,这必须由客户来完成。当然,它将提供发出请求时使用的requestID。客户端需要记住每个requestID的用途,并决定在回调中接收到该信息时如何处理该信息。这可以通过字典或哈希表来完成,在回调中接收数据后,检查链是否完整。
来自API的消息传递通常会产生意外的结果,接收额外的消息是很常见的,这是客户端需要考虑的问题。考虑API是无状态的,并跟踪客户端中的所有内容。
看来你指的是监管快照,我鼓励你考虑一下成本。这可能很快就会增加流媒体直播数据的价格。再加上1秒的限制将使链条需要很长时间才能加载。我甚至不建议使用带有实时数据的快照,自己取消请求是微不足道的,而且速度要快得多。
类似(这显然是不完整的C#,只是一个起点(
class OptionData
{
public int ReqId { get; }
public double Strike { get; }
public string Expiry { get; }
public double? Bid { get; set; } = null;
public double? Ask { get; set; } = null;
public bool IsComplete()
{
return Bid != null && Ask != null;
}
public OptionData(int reqId, double strike, ....
{ ...
}
...
class MyData()
{
// Create somewhere to store our data, indexed by reqId.
Dictionary<int, OptionData> optChain = new();
public MyData()
{
// We would want to call reqSecDefOptParams to get a list of strikes etc.
// Choose which part of the chain you want, likely you'll want to
// get the current price of the underlying to decide.
int reqId = 1;
...
optChain.Add(++reqId, new OptionData(reqId,strike,expiry));
...
// Request data for each contract
// Note the 50 msg/sec limit https://interactivebrokers.github.io/tws-api/introduction.html#fifty_messages
// Only 1/sec for Reg snapshot
foreach(OptionData opt in optChain)
{
Contract con = new()
{
Symbol = "SPY",
Currency = "USD"
Exchange = "SMART",
Right = "C",
SecType = "OPT",
Strike = opt.strike,
Expiry = opt.Expiry
};
ibClient.ClientSocket.reqMktData(opt.ReqId, con, "", false, true, new List<TagValue>());
}
}
...
private void Recv_TickPrice(TickPriceMessage msg)
{
if(optChain.ContainsKey(msg.RequestId))
{
if (msg.Field == 2) optChain[msg.RequestId].Ask = msg.Price;
if (msg.Field == 1) optChain[msg.RequestId].Bid = msg.Price;
// You may want other tick types as well
// see https://interactivebrokers.github.io/tws-api/tick_types.html
if(optChain[msg.RequestId].IsComplete())
{
// This wont apply for reg snapshot.
ibClient.ClientSocket.cancelMktData(msg.RequestId);
// You have the data, and have cancelled the request.
// Maybe request more data or update display etc...
// Check if the whole chain is complete
bool complete=true;
foreach(OptionData opt in optChain)
if(!opt.IsComplete()) complete=false;
if(complete)
// do whatever
}
}
}