我正在尝试制作我的第一个算法机器人,并决定与 IB 合作并使用他们的 API。我关注了 Jacob Aramral 的关于制作机器人的 YouTube 系列,并且基本上遵循并添加了一些调整,以使逻辑按照我想要的方式执行。尝试运行代码后,我不断收到有关无法连接的错误。所以,我只是复制了他的代码并尝试运行它(https://github.com/Jake0303/InteractiveBrokersPythonBot/blob/main/InteractiveBrokersPythonBot.py)。它连接到 TWS(我假设是 IB 服务器),我可以输入股票代码并获取实时数据,但它不会进行交易。然后,我调整了雅各布的代码,基本上在每根蜡烛上进行交易(只是因为它正在读取我的纸质账户,并且我想看到进行任何交易),但是当满足标准时(最后收盘价高于之前蜡烛的收盘价)没有进行任何交易。我开始有点沮丧,所以希望有人能帮助我。我也尝试复制这里的介绍指南来尝试让 TWS 进行交易,但仍然没有成功。如果有人能看到我做错了什么并可以帮助我解决它,我将不胜感激。
我的 IBpro 账户由游戏资金提供资金,并订阅了“美国股票和期权附加流媒体捆绑包”和“美国证券快照和期货价值捆绑包”订阅。对于纸质账户,我使用 7497 作为套接字端口,检查了 Active X 和套接字客户端,并禁用了只读 API。我相信这就是我需要启用的所有功能,以允许 API 为我进行交易(除了有功能代码,哈哈)。这是应该可以工作的代码。我很好奇它是否适用于其他和地方交易。另外,代码运行后我还添加了监视器的片段。如有任何帮助,我们将不胜感激!
#Imports
import ibapi
from ibapi.client import EClient
from ibapi.wrapper import EWrapper
from ibapi.contract import Contract
from ibapi.order import *
import ta
import numpy as np
import pandas as pd
import pytz
import math
from datetime import datetime, timedelta
import threading
import time
#Vars
orderId = 1
#Class for Interactive Brokers Connection
class IBApi(EWrapper,EClient):
def __init__(self):
EClient.__init__(self, self)
# Historical Backtest Data
def historicalData(self, reqId, bar):
try:
bot.on_bar_update(reqId,bar,False)
except Exception as e:
print(e)
# On Realtime Bar after historical data finishes
def historicalDataUpdate(self, reqId, bar):
try:
bot.on_bar_update(reqId,bar,True)
except Exception as e:
print(e)
# On Historical Data End
def historicalDataEnd(self, reqId, start, end):
print(reqId)
# Get next order id we can use
def nextValidId(self, nextorderId):
global orderId
orderId = nextorderId
# Listen for realtime bars
def realtimeBar(self, reqId, time, open_, high, low, close,volume, wap, count):
super().realtimeBar(reqId, time, open_, high, low, close, volume, wap, count)
try:
bot.on_bar_update(reqId, time, open_, high, low, close, volume, wap, count)
except Exception as e:
print(e)
def error(self, id, errorCode, errorMsg):
print(errorCode)
print(errorMsg)
#Bar Object
class Bar:
open = 0
low = 0
high = 0
close = 0
volume = 0
date = datetime.now()
def __init__(self):
self.open = 0
self.low = 0
self.high = 0
self.close = 0
self.volume = 0
self.date = datetime.now()
#Bot Logic
class Bot:
ib = None
barsize = 1
currentBar = Bar()
bars = []
reqId = 1
global orderId
smaPeriod = 50
symbol = ""
initialbartime = datetime.now().astimezone(pytz.timezone("America/New_York"))
def __init__(self):
#Connect to IB on init
self.ib = IBApi()
self.ib.connect("127.0.0.1", 7497,221)
ib_thread = threading.Thread(target=self.run_loop, daemon=True)
ib_thread.start()
time.sleep(1)
currentBar = Bar()
#Get symbol info
self.symbol = input("Enter the symbol you want to trade : ")
#Get bar size
self.barsize = int(input("Enter the barsize you want to trade in minutes : "))
mintext = " min"
if (int(self.barsize) > 1):
mintext = " mins"
queryTime = (datetime.now().astimezone(pytz.timezone("America/New_York"))-timedelta(days=1)).replace(hour=16,minute=0,second=0,microsecond=0).strftime("%Y%m%d %H:%M:%S")
#Create our IB Contract Object
contract = Contract()
contract.symbol = self.symbol.upper()
contract.secType = "STK"
contract.exchange = "SMART"
contract.currency = "USD"
self.ib.reqIds(-1)
# Request Market Data
#self.ib.reqRealTimeBars(0, contract, 5, "TRADES", 1, [])
self.ib.reqHistoricalData(self.reqId,contract,"","2 D",str(self.barsize)+mintext,"TRADES",1,1,True,[])
#Listen to socket in seperate thread
def run_loop(self):
self.ib.run()
#Bracet Order Setup
def bracketOrder(self, parentOrderId, action, quantity, profitTarget, stopLoss):
#Initial Entry
#Create our IB Contract Object
contract = Contract()
contract.symbol = self.symbol.upper()
contract.secType = "STK"
contract.exchange = "SMART"
contract.currency = "USD"
# Create Parent Order / Initial Entry
parent = Order()
parent.orderId = parentOrderId
parent.orderType = "MKT"
parent.action = action
parent.totalQuantity = quantity
parent.transmit = False
# Profit Target
profitTargetOrder = Order()
profitTargetOrder.orderId = parent.orderId+1
profitTargetOrder.orderType = "LMT"
profitTargetOrder.action = "SELL"
profitTargetOrder.totalQuantity = quantity
profitTargetOrder.lmtPrice = round(profitTarget,2)
profitTargetOrder.parentId = parentOrderId
profitTargetOrder.transmit = False
# Stop Loss
stopLossOrder = Order()
stopLossOrder.orderId = parent.orderId+2
stopLossOrder.orderType = "STP"
stopLossOrder.action = "SELL"
stopLossOrder.totalQuantity = quantity
stopLossOrder.parentId = parentOrderId
stopLossOrder.auxPrice = round(stopLoss,2)
stopLossOrder.transmit = True
bracketOrders = [parent, profitTargetOrder, stopLossOrder]
return bracketOrders
#Pass realtime bar data back to our bot object
def on_bar_update(self, reqId, bar,realtime):
global orderId
#Historical Data to catch up
if (realtime == False):
self.bars.append(bar)
else:
bartime = datetime.strptime(bar.date,"%Y%m%d %H:%M:%S").astimezone(pytz.timezone("America/New_York"))
minutes_diff = (bartime-self.initialbartime).total_seconds() / 60.0
self.currentBar.date = bartime
lastBar = self.bars[len(self.bars)-1]
#On Bar Close
if (minutes_diff > 0 and math.floor(minutes_diff) % self.barsize == 0):
self.initialbartime = bartime
#Entry - If we have a higher high, a higher low and we cross the 50 SMA Buy
#1.) SMA
closes = []
for bar in self.bars:
closes.append(bar.close)
self.close_array = pd.Series(np.asarray(closes))
self.sma = ta.trend.sma(self.close_array,self.smaPeriod,True)
print("SMA : " + str(self.sma[len(self.sma)-1]))
#2.) Calculate Higher Highs and Lows
lastLow = self.bars[len(self.bars)-1].low
lastHigh = self.bars[len(self.bars)-1].high
lastClose = self.bars[len(self.bars)-1].close
# Check Criteria
if (bar.close > lastHigh
and self.currentBar.low > lastLow
and bar.close > str(self.sma[len(self.sma)-1])
and lastClose < str(self.sma[len(self.sma)-2])):
#Bracket Order 2% Profit Target 1% Stop Loss
profitTarget = bar.close*1.02
stopLoss = bar.close*0.99
quantity = 1
bracket = self.bracketOrder(orderId,"BUY",quantity, profitTarget, stopLoss)
contract = Contract()
contract.symbol = self.symbol.upper()
contract.secType = "STK"
contract.exchange = "SMART"
contract.currency = "USD"
#Place Bracket Order
for o in bracket:
o.ocaGroup = "OCA_"+str(orderId)
self.ib.placeOrder(o.orderId,contract,o)
orderId += 3
#Bar closed append
self.currentBar.close = bar.close
print("New bar!")
self.bars.append(self.currentBar)
self.currentBar = Bar()
self.currentBar.open = bar.open
#Build realtime bar
if (self.currentBar.open == 0):
self.currentBar.open = bar.open
if (self.currentBar.high == 0 or bar.high > self.currentBar.high):
self.currentBar.high = bar.high
if (self.currentBar.low == 0 or bar.low < self.currentBar.low):
self.currentBar.low = bar.low
#Start Bot
bot = Bot()
进行了一些调整,包括不满足标准时显示消息。 应该让你开始
#Imports
import ibapi
from ibapi.client import EClient
from ibapi.wrapper import EWrapper
from ibapi.contract import Contract
from ibapi.order import *
import pandas as pd
import pytz
import math
from datetime import datetime, timedelta
import threading
import time
#Vars
orderId = 1
#Class for Interactive Brokers Connection
class IBApi(EWrapper,EClient):
def __init__(self):
EClient.__init__(self, self)
# Historical Backtest Data
def historicalData(self, reqId, bar):
try:
myBar = Bar()
myBar.open = bar.open
myBar.low = bar.low
myBar.high = bar.high
myBar.close = bar.close
myBar.volume = bar.volume
myBar.date = pytz.timezone("America/New_York").localize(datetime.strptime(bar.date[:17], "%Y%m%d %H:%M:%S"))
bot.on_bar_update(reqId,myBar,False)
except Exception as e:
print("historicalData Ex: ",e)
# On Historical Data End
def historicalDataEnd(self, reqId, start, end):
try:
print("\nHistorical data recieved: ",start," to ",end)
print("Waiting for next bar close....")
contract = Contract()
contract.symbol = bot.symbol.upper()
contract.secType = "STK"
contract.exchange = "SMART"
contract.currency = "USD"
bot.ib.reqRealTimeBars(2, contract, 5, "TRADES", False, [])
except Exception as e:
print("historicalDataEnd Ex: ",e)
# Get next order id we can use
def nextValidId(self, nextorderId):
global orderId
orderId = nextorderId
# Listen for realtime bars
def realtimeBar(self, reqId, time, open_, high, low, close,volume, wap, count):
super().realtimeBar(reqId, time, open_, high, low, close, volume, wap, count)
bar = Bar()
bar.open = open_
bar.low = low
bar.high = high
bar.close = close
bar.volume = volume
bar.date = datetime.fromtimestamp(time, pytz.timezone("America/New_York"))
bot.on_bar_update(reqId, bar, True)
def error(self, id, errorCode, errorMsg, advOrdRej): # Depending on API version advOrdRej may not be required
print(errorCode,": ",errorMsg)
#Bar Object
class Bar:
open = 0
low = 0
high = 0
close = 0
volume = 0
date = datetime.now()
def __init__(self):
self.open = 0
self.low = 0
self.high = 0
self.close = 0
self.volume = 0
self.date = datetime.now()
#Bot Logic
class Bot:
ib = None
barsize = 1
currentBar = Bar()
bars = []
reqId = 1
global orderId
smaPeriod = 50
symbol = ""
nextBarTime = 0
def __init__(self):
#Connect to IB on init
self.ib = IBApi()
self.ib.connect("127.0.0.1", 7497,221)
ib_thread = threading.Thread(target=self.run_loop, daemon=True)
ib_thread.start()
time.sleep(1)
currentBar = Bar()
#Get symbol info
self.symbol = input("Enter the symbol you want to trade : ")
#Get bar size
self.barsize = int(input("Enter the barsize you want to trade in minutes : "))
mintext = " min"
if (int(self.barsize) > 1):
mintext = " mins"
secs = 60 * self.barsize * 200 # barcount to retrieve
queryTime = (datetime.now().astimezone(pytz.timezone("America/New_York"))-timedelta(seconds=secs)).strftime("%Y%m%d %H:%M:%S")
#Create our IB Contract Object
contract = Contract()
contract.symbol = self.symbol.upper()
contract.secType = "STK"
contract.exchange = "SMART"
contract.currency = "USD"
self.ib.reqIds(-1)
# Request History
self.ib.reqHistoricalData(1,contract,"",str(secs)+" S",str(self.barsize)+mintext,"TRADES",0,1,False,[])
#Listen to socket in seperate thread
def run_loop(self):
self.ib.run()
#Bracet Order Setup
def bracketOrder(self, parentOrderId, action, quantity, profitTarget, stopLoss):
#Initial Entry
#Create our IB Contract Object
contract = Contract()
contract.symbol = self.symbol.upper()
contract.secType = "STK"
contract.exchange = "SMART"
contract.currency = "USD"
# Create Parent Order / Initial Entry
parent = Order()
parent.orderId = parentOrderId
parent.orderType = "MKT"
parent.action = action
parent.totalQuantity = quantity
parent.transmit = False
# Profit Target
profitTargetOrder = Order()
profitTargetOrder.orderId = parent.orderId+1
profitTargetOrder.orderType = "LMT"
profitTargetOrder.action = "SELL"
profitTargetOrder.totalQuantity = quantity
profitTargetOrder.lmtPrice = round(profitTarget,2)
profitTargetOrder.parentId = parentOrderId
profitTargetOrder.transmit = False
# Stop Loss
stopLossOrder = Order()
stopLossOrder.orderId = parent.orderId+2
stopLossOrder.orderType = "STP"
stopLossOrder.action = "SELL"
stopLossOrder.totalQuantity = quantity
stopLossOrder.parentId = parentOrderId
stopLossOrder.auxPrice = round(stopLoss,2)
stopLossOrder.transmit = True
bracketOrders = [parent, profitTargetOrder, stopLossOrder]
return bracketOrders
#Pass realtime bar data back to our bot object
def on_bar_update(self, reqId, bar, realtime):
global orderId,nextBarTime,currentBar
try:
#Historical Data to catch up
if (realtime == False):
self.bars.append(bar)
self.nextBarTime = bar.date+timedelta(seconds=60 * self.barsize)
else:
if (bar.date >= self.nextBarTime):
#On Bar Close
self.bars.append(self.currentBar)
print("Bar Closed ",self.currentBar.date.strftime('%H:%M')," o:",self.currentBar.open," h:",self.currentBar.high," l:",self.currentBar.low," c:",self.currentBar.close)
# Calc SMA
closes = []
for bar in self.bars:
closes.append(bar.close)
numbers_series = pd.Series(closes)
windows = numbers_series.rolling(self.smaPeriod)
moving_averages = windows.mean()
sma = moving_averages.tolist()
# Calculate Higher Highs and Lows
lastLow = self.bars[len(self.bars)-1].low
lastHigh = self.bars[len(self.bars)-1].high
lastClose = self.bars[len(self.bars)-1].close
# Check Criteria
if (self.currentBar.close > lastHigh
and self.currentBar.low > lastLow
and self.currentBar.close > sma[len(sma)-1]
and lastClose < sma[len(sma)-2]):
print("Placing Order")
#Bracket Order 2% Profit Target 1% Stop Loss
profitTarget = bar.close*1.02
stopLoss = bar.close*0.99
quantity = 1
bracket = self.bracketOrder(orderId,"BUY",quantity, profitTarget, stopLoss)
contract = Contract()
contract.symbol = self.symbol.upper()
contract.secType = "STK"
contract.exchange = "SMART"
contract.currency = "USD"
#Place Bracket Order
for o in bracket:
o.ocaGroup = "OCA_"+str(orderId)
self.ib.placeOrder(o.orderId,contract,o)
orderId += 3
else:
if(self.currentBar.close <= lastHigh):
print("-- Criteria not met: 'self.currentBar.close > lastHigh' Close:",self.currentBar.close," lastHigh:",lastHigh)
if(self.currentBar.low <= lastLow):
print("-- Criteria not met: 'self.currentBar.low > lastLow' Low:",self.currentBar.close," lastLow:",lastLow)
if(self.currentBar.close <= sma[len(sma)-1]):
print("-- Criteria not met: 'self.currentBar.close > sma[len(sma)-1]' Close:",self.currentBar.close," sma:",sma[len(sma)-1])
if(lastClose >= sma[len(sma)-2]):
print("-- Criteria not met: 'lastClose < sma[len(sma)-2]' lastClose:",lastClose," sma:",sma[len(sma)-2])
# Create new bar
self.currentBar = Bar()
self.currentBar.open = bar.open
self.currentBar.high = bar.high
self.currentBar.low = bar.low
self.currentBar.close = bar.close
self.currentBar.date = self.nextBarTime #bar.date
self.nextBarTime += timedelta(seconds=60 * self.barsize)
else:
#Build realtime bar
if (self.currentBar.open == 0):
self.currentBar.open = bar.open
if (self.currentBar.high == 0 or bar.high > self.currentBar.high):
self.currentBar.high = bar.high
if (self.currentBar.low == 0 or bar.low < self.currentBar.low):
self.currentBar.low = bar.low
self.currentBar.close = bar.close
except Exception as e:
print("on_bar_update Ex: ",e)
#Start Bot
bot = Bot()
首先,感谢您找到这个讨论。附加的代码对我也有帮助。然而,我发现,在原始 GitHub 文件和此处的代码中,“最后”值以某种方式立即更新为当前值,这意味着以下打印将始终相同:
print("self.currentBar.Close:",self.currentBar.close) 打印(“最后关闭:”,最后关闭) if (self.currentBar.close > LastClose):
我还测试了:“if (self.currentBar.close == lastClose):”并且它确实进行了交易..
如果有人可以帮助让lastClose真正成为最后一次关闭而不是currentBar.Close?