Hi guys am just starting to work on an Ibpy algorithm and i would like to test it with paper trading first but i have a little understanding how to use the reqMktData to get the last price. I have no problem placing orders but this returns nothing for 25 seconds, Im thinking that it is only to be used during trading hours or maybe am just using it wrong any thoughts?
from ib.opt import ibConnection, message
from ib.ext.Contract import Contract
from time import sleep
def my_callback_handler(msg):
inside_mkt_bid = ''
inside_mkt_ask = ''
if msg.field == 1:
inside_mkt_bid = msg.price
print 'bid', inside_mkt_bid
elif msg.field == 2:
inside_mkt_ask = msg.price
print 'ask', inside_mkt_ask
tws = ibConnection()
tws.register(my_callback_handler, message.tickSize, message.tickPrice)
tws.connect()
c = Contract()
c.m_symbol = "DATA"
c.m_secType = "STK"
c.m_exchange = "SMART"
c.m_currency = "USD"
tws.reqMktData(788,c,"",False)
sleep(25)
print 'All done'
tws.disconnect()
I have try IbPy before and successfully get the data but now I have use Ibapi instead which is more difficult and still can't fully trade in it but it has an adjusted historical price.
So this is my code which you have to tailor what so you want.
1.Get the stock member form Excel
from ib.opt import ibConnection, message
from ib.ext.Contract import Contract
from ib.ext.Order import Order
from ib.ext.TickType import TickType as tt
from time import sleep, time, strftime
import datetime
from __future__ import print_function #I'm using 3.x style print
import pandas as pd
import numpy as np
from math import ceil
import re
xls_file = pd.ExcelFile('xxxx\\Interactive_Broker_trading\\SNP2.xlsx')
df = xls_file.parse('Sheet1')
Ticker = df.iloc[:,1]
all_data = pd.DataFrame(Ticker)
all_data.columns = ['ticker']
all_data['type'] = 'STK'
all_data['exchange'] = 'SMART'
all_data['curr'] = 'USD'
all_data['bidPrice'] =0
all_data['askPrice'] =0
all_data['lastPrice'] =0
all_data['HistoryPrice']=0
2.Get the Historical Price by using for loop since my account has a limit of 100 request per moment so I devide it into 8 multiple sessions for S&P 505. Then relogin at each 70 stocks. I can get the total of 505 in 2 minutes.
def error_handler(msg):
print(msg)
def my_callback_handler(msg):
if msg.field in [tt.BID,tt.ASK,tt.LAST]:
# from ib.ext.TickType import TickType as tt
#now we can just store the response in the data frame
all_data.loc[msg.tickerId,tt.getField(msg.field)] = msg.price
# if msg.field == tt.LAST:
# # print('a')
# print(all_data.loc[msg.tickerId,'ticker'],msg.price)
t = time()
max_amount_per_Iter = 70 #max number per iter to save cost
max_Iter = ceil(len(all_data)/max_amount_per_Iter)
for i in range (0,max_Iter):
print('====================for : ',i+1,'==========================')
sleep(1)
tws = ibConnection(clientId=11+i)
tws.register(my_callback_handler, message.tickPrice, message.tickSize)
tws.register(error_handler, 'Error')
tws.connect()
all_dum = all_data.iloc[i*max_amount_per_Iter:min((i+1)*max_amount_per_Iter,len(all_data)),:]
for index, row in all_dum.iterrows():
c = Contract()
c.m_symbol = row['ticker']
c.m_exchange = row['exchange']
c.m_currency = row['curr']
c.m_secType = row['type']
# the tickerId is just the index in but for some reason it needs str()
tws.reqMktData(str(index),c,'',False)
sleep(0.2)
sleep(2)
print('=========End round : ',i+1,'with time :',time() - t,'==============')
tws.disconnect()
I'm thinking it has something to do with the market data subscription within IB itself because I am having a similar problem. I get a TWS Time at connection... returned in the results along with the "market data farm connection" Msg.
Make sure you have a connection port & clientID established, i.e.:
tws = ibConnection(port=7496,clientId=100)
Note that 7496 is a common port, but the clientId is anything you wish to specify (within the IB account you are using under File->API->Settings).
Related
First one:
### configuration details
TELEGRAM_TOKEN = '' # telegram bot token
TELEGRAM_CHANNEL ='' # channel id
INTERVAL = '1m' # binance time interval
SHORT_EMA = 7 # short interval for ema
LONG_EMA = 21 # long interval for ema
Here is my second code:
import requests
import talib
import time
import numpy as np
import websocket
from config import TELEGRAM_TOKEN, TELEGRAM_CHANNEL , INTERVAL, SHORT_EMA , LONG_EMA
def streamKline(currency, interval):
websocket.enableTrace(False)
socket = f'wss://stream.binance.com:9443/ws/{currency}#kline_{interval}'
ws = websocket.WebSocketApp(socket)
ws.run_forever()
#SYMBOLS TO LOOK FOR ALERTS
SYMBOLS = [
"ETHUSDT",
"BTCUSDT",
"ATOMUSDT",
"BNBUSDT",
"FTMBUSD",
"ENJUSDT",
"WAXPUSDT"
]
#sending alerts to telegram
def send_message(message):
url = "https://api.telegram.org/bot{}/sendMessage?chat_id={}&text={}&parse_mode=markdown".format(TELEGRAM_TOKEN,TELEGRAM_CHANNEL,message)
res = requests.get(url);print(url);
return res
# getting klines data to process
def streamKline(symbol):
data = socket.streamKline(symbol=symbol,interval=INTERVAL,limit=300) # more data means more precision but at the trade off between speed and time
return_data = []
# taking closing data for each kline
for each in data:
return_data.append(float(each[4])) # 4 is the index of the closing data in each kline
return np.array(return_data) # returning as numpy array for better precision and performance
def main():
# making a infinite loop that keeps checking for condition
while True:
#looping through each coin
for each in SYMBOLS:
data = streamKline(each)
ema_short = talib.EMA(data,int(SHORT_EMA))
ema_long = talib.EMA(data,int(LONG_EMA))
last_ema_short = ema_short[-2]
last_ema_long = ema_long[-2]
ema_short = ema_short[-1]
ema_long = ema_long[-1]
# conditions for alerts
if(ema_short > ema_long and last_ema_short < last_ema_long):
message = each + "bullcoming "+ str(SHORT_EMA) + " over "+str(LONG_EMA);print(each ,"alert came");
send_message(message);
time.sleep(0.5);
# calling the function
if __name__ == "__main__":
main()
The part of config is all settle done, just second for the kline data, the error mention lot like this.
data = socket.streamKline(symbol=symbol,interval=INTERVAL,limit=300) # more data means more precision but at the
trade off between speed and time
NameError: name 'socket' is not defined
I just don't know how to do it, I want build a ema alert that can give me a message when I am not watching chart, through this way seems not work, I have tried many times, and also find many video but still, I am just an beginner, nothing improving at all.
I'm new to Python (programming in general) and I've been trying to learn myself through youtube and sites like stackoverflow. In the meantime I've programmed a working trading bot in binance. But now I'm working on a tweak in this bot on the sell part, which I cannot get working. Trying the parameters standalone does work, but when I combine the two it does not work. I'm doing something wrong, but can't figure out what it is. (It still does buy, but does not sell.)
In the code, on the SELL part, everything works just fine when I change TRADE_QUANTITY_SELL for TRADE_QUANTITY_BUY (so it uses the same value on both buy and sell order).
The sell part does work, when I try this standalone:
balance = client.get_asset_balance(asset='BTC')
FREEBTC = float(balance['free'])
TRADE_QUANTITY_SELL = round(FREEBTC, 5)
#print (TRADE_QUANTITY_SELL)
order = client.create_test_order(
symbol=TRADE_SYMBOL,
side=SIDE_SELL,
type=ORDER_TYPE_MARKET,
quantity=TRADE_QUANTITY_SELL)
print(order)
This is the complete bot version I've tried last. It still does buy, but does not sell.
import websocket, json, pprint, talib, numpy
import config
from binance.client import Client
from binance.enums import *
SOCKET = "wss://stream.binance.com:9443/ws/btceur#kline_5m"
RSI_PERIOD = 14
RSI_OVERBOUGHT = 70
RSI_OVERSOLD = 30
TRADE_SYMBOL = 'BTCEUR'
TRADE_QUANTITY_BUY = 0.002
closes = []
client = Client(config.API_KEY, config.API_SECRET)
balance = client.get_asset_balance(asset='BTC')
FREEBTC = float(balance['free'])
TRADE_QUANTITY_SELL = round(FREEBTC, 6)
#print(SELL_TOTAL)
def order(side, quantity, symbol, order_type=ORDER_TYPE_MARKET):
try:
print("sending order")
order = client.create_order(symbol=symbol, side=side, type=order_type, quantity=quantity)
print(order)
except Exception as e:
print("an exception occured - {}".format(e))
return False
return True
def on_open(ws):
print('opened connection')
def on_close(ws):
print('closed connection')
def on_message(ws, message):
global closes
print('received message')
json_message = json.loads(message)
pprint.pprint(json_message)
candle = json_message['k']
is_candle_closed = candle['x']
close = candle['c']
in_position = False
#also tried to put the TRADE_QUANTITY_SELL params here, also does not work
if is_candle_closed:
print("candle closed at {}".format(close))
closes.append(float(close))
print("closes")
print(closes)
if len(closes) > RSI_PERIOD:
np_closes = numpy.array(closes)
rsi = talib.RSI(np_closes, RSI_PERIOD)
print("all rsis calculated so far")
print(rsi)
last_rsi = rsi[-1]
print("the current rsi is {}".format(last_rsi))
if last_rsi > RSI_OVERBOUGHT:
if in_position:
print("Overbought! Sell! Sell! Sell!")
#put binance order logic here
order_succeeded = order(SIDE_SELL, TRADE_QUANTITY_SELL, TRADE_SYMBOL)
if order_succeeded:
in_position = False
else:
print("It is overbought, but we don't own any. Nothing to do.")
if last_rsi < RSI_OVERSOLD:
if in_position:
print("Oversold! Buy! Buy! Buy!")
#print("It is oversold, but you already own it, nothing to do")
order_succeeded = order(SIDE_BUY, TRADE_QUANTITY_BUY, TRADE_SYMBOL)
if order_succeeded:
in_position = True
else:
print("Oversold! Buy! Buy! Buy!")
#put binance order logic here
order_succeeded = order(SIDE_BUY, TRADE_QUANTITY_BUY, TRADE_SYMBOL)
if order_succeeded:
in_position = True
ws = websocket.WebSocketApp(SOCKET, on_open=on_open, on_close=on_close, on_message=on_message)
ws.run_forever( )
I'm not sure if this part
if last_rsi > RSI_OVERBOUGHT:
if in_position:
will ever be in_position eq True
in_position = False is create localy and when on_message ends it is still there in python(in some languages may not) but... next time on_message is called it will be overriten to False
Am I right?
move in_position = False to the top and see if it works
In the part that works...
balance = client.get_asset_balance(asset='BTC')
FREEBTC = float(balance['free'])
TRADE_QUANTITY_SELL = round(FREEBTC, 5)
#print (TRADE_QUANTITY_SELL)
order = client.create_test_order(
symbol=TRADE_SYMBOL,
side=SIDE_SELL,
type=ORDER_TYPE_MARKET,
quantity=TRADE_QUANTITY_SELL)
print(order)
...the code rounds to a precision of 5 decimal points, while in the code that doesn't work...
import websocket, json, pprint, talib, numpy
import config
from binance.client import Client
from binance.enums import *
SOCKET = "wss://stream.binance.com:9443/ws/btceur#kline_5m"
RSI_PERIOD = 14
RSI_OVERBOUGHT = 70
RSI_OVERSOLD = 30
TRADE_SYMBOL = 'BTCEUR'
TRADE_QUANTITY_BUY = 0.002
closes = []
client = Client(config.API_KEY, config.API_SECRET)
balance = client.get_asset_balance(asset='BTC')
FREEBTC = float(balance['free'])
TRADE_QUANTITY_SELL = round(FREEBTC, 6)
#print(SELL_TOTAL)
# ...
...it rounds to a precision of 6 decimal points. TRADE_QUANTITY_BUY is at a precision of 3 decimal points; less precise than both. To me, this suggests that perhaps a transaction of lesser than 0.00001 for your particular "coin" at a time is invalid through your API, causing them to be blocked.
My advice: check that the binance library you are using supports sell orders of that amount, since sell orders they may be filtered.
This all comes from a quick search: this library you are using may have more specific information on minimum/maximum order prices.
I took the below code from one of the answered queries in Stackoverflow (unfortunately i cannot give full credit as i cannot locate the page anymore). I changed it a bit to fit my purpose.
I want to extract historical Reuters data (fundamentalData) for a list of tickers. The below code works fine but it only grabs the last ticker data. I know i need to build a while loop but i tried many times and none worked. I'm sure this is a quick fix but since I am new at coding and python in general I just can't find the solution. Any help would be appreciated!
#Import all libriaries
from ib.opt import ibConnection, message
from time import sleep
import lxml.etree
from bs4 import BeautifulSoup
import pandas as pd
import numpy as np
from IPython.core.debugger import set_trace
from ibapi import wrapper
from ibapi.client import EClient
from ibapi.common import *
from ibapi.contract import Contract
#upload excel file of list of company tickers you want to review
us_list= pd.read_excel(r'C:\TWS API\Request Reuters data\Quant Project IB TWS_test.xlsx', engine='openpyxl')
stocksList = us_list[['TICKER']]
stocksList
def fundamentalData_handler(msg):
global imported
imported = msg.data
def error_handler(msg):
pass
# processing of the lines in financial statements
def extractVauleFromLineItem(fiscalperiod, code):
stage1 = fiscalperiod.find(name='lineitem', coacode=code)
if (not stage1 is None):
stage2 = stage1.get_text()
if (stage2 == stage2):
stage3 = float(stage2)
if (stage3 == stage3):
return (stage3)
else:
return (0.0)
result = pd.DataFrame(columns =['Year', 'Ticker','control','TotalRevenue', 'GrossProfit', 'CommonSharesOutstanding','DilutedNormalizedEPS', 'totalCash', 'TotalDebt','Dividends'])
outcomes = []
for i, row in stocksList.iterrows():
contract = Contract()
contract.symbol = row['TICKER']
contract.secType = "STK"
contract.currency = "USD"
contract.exchange = "SMART"
tws = ibConnection("127.0.0.1",port=7497, clientId=901)
tws.register(error_handler, message.Error)
tws.register(fundamentalData_handler, message.fundamentalData)
tws.connect()
tws.reqFundamentalData(1,contract,'ReportsFinStatements')
sleep(1)
tws.disconnect()
print(contract.symbol)
soup = BeautifulSoup(imported) # library for processing of the obtained XML data
data = []
print(soup.find(name='issueid', type="Ticker").get_text())
print(soup.find(name='coid', type="CompanyName").get_text())
# I found that IB API is not very stable.
# Sometimes it returns data of the wrong company.
# So the control is important
print('Control -',contract.symbol == soup.find(name='issueid', type="Ticker").get_text())
print()
for fiscalperiod in soup.find_all(name="fiscalperiod", type="Annual"):
year = fiscalperiod['fiscalyear']
TotalRevenue = extractVauleFromLineItem(fiscalperiod, 'RTLR')
GrossProfit = extractVauleFromLineItem(fiscalperiod, 'SGRP')
CommonSharesOutstanding = extractVauleFromLineItem(fiscalperiod, 'QTCO')
DilutedNormalizedEPS = extractVauleFromLineItem(fiscalperiod, 'VDES')
totalCash = extractVauleFromLineItem(fiscalperiod, 'OTLO')
TotalDebt = extractVauleFromLineItem(fiscalperiod, 'STLD')
Dividends = extractVauleFromLineItem(fiscalperiod, 'FCDP')
thisYearData = (year,contract.symbol, (contract.symbol == soup.find(name='issueid', type="Ticker").get_text()),TotalRevenue , GrossProfit, CommonSharesOutstanding, totalCash, TotalDebt, Dividends)
data.append(thisYearData)
df_data = pd.DataFrame(data, columns =['Year','control','TotalRevenue', 'GrossProfit', 'CommonSharesOutstanding','DilutedNormalizedEPS', 'totalCash', 'TotalDebt','Dividends'])
df_data = df_data.sort_values(by=['Year'])
I was able to piece together a script from IB's documentation/examples and forums on this site. I am getting the output I want for a single symbol, however, if I use a list of stocks, I cannot figure out a way to pass the ticker symbol through to the DF output file. My workaround was to create a dictionary that uses the list sequence (see below) however the output from IB's api changes slightly each time rendering the symbols mostly pointless. The list i am using below normally has 20+ names but may change, i cut it down to make it easier to view.
#Brian/and or other developers, if there is a way to create either a unique ID/sequence for each symbol call and stamp it to data that is brought back, i can then utilize a dictionary to apply the symbol. In the other forum, you passed in a line where n_id = n_id +1, if that can be applied and is linked to each specific call which is done in order of the list, then that could work?
from ibapi.client import EClient
from ibapi.wrapper import EWrapper
from ibapi.contract import Contract
import pandas as pd
import threading
import time
from datetime import timedelta
import datetime
class IBapi(EWrapper, EClient):
def __init__(self):
EClient.__init__(self, self)
self.data = [] #Initialize variable to store candle
def historicalData(self, reqId, bar):
#print(f'Time: {bar.date} Close: {bar.close} Volume: {bar.volume}',reqId)
self.data.append([bar.date, bar.close, bar.volume, reqId])
def run_loop():
app.run()
app = IBapi()
app.connect('127.0.0.1', 7496, 123)
#Start the socket in a thread
api_thread = threading.Thread(target=run_loop, daemon=True)
api_thread.start()
time.sleep(1) #Sleep interval to allow time for connection to server
symbols = ['SPY','MSFT','GOOG','AAPL','QQQ','IWM','TSLA']
for sym in symbols:
contract = Contract()
contract.symbol = str(sym)
contract.secType = "STK"
contract.exchange = "SMART"
contract.currency = "USD"
#contract.primaryExchange = "ISLAND"
app.reqHistoricalData(1, contract, "", "1 D", "10 mins", "ADJUSTED_LAST", 1, 2, False, [])
time.sleep(5) #sleep to allow enough time for data to be returned
df = pd.DataFrame(app.data, columns=['DateTime', 'ADJUSTED_LAST','Volume','reqId'])
df['DateTime'] = pd.to_datetime(df['DateTime'],unit='s') #,unit='s')
df['Count'] = df.groupby('DateTime').cumcount()+1
sym_dict = {1:'SPY',2:'MSFT',3:'GOOG',4:'AAPL',5:'QQQ',6:'IWM',7:'TSLA'}
df['Ticker'] = df['Count'].map(sym_dict)
print(df)
#edit, adding in #Brian's detail:
from ibapi.client import EClient
from ibapi.wrapper import EWrapper
from ibapi.contract import Contract
import pandas as pd
import time
from datetime import timedelta
import datetime
start = datetime.datetime.utcnow()
class IBapi(EWrapper, EClient):
def __init__(self):
EClient.__init__(self, self)
self.data = []
def error(self, reqId, errorCode, errorString):
print("Error. Id: " , reqId, " Code: " , errorCode , " Msg: " , errorString)
def historicalData(self, reqId, bar):
self.data.append([bar.date, bar.close, bar.volume, sym_dict[reqId]])
print("HistoricalData. ReqId:", sym_dict[reqId], "BarData.", bar)
# include this callback to track progress and maybe disconnectwhen all are finished
def historicalDataEnd(self, reqId: int, start: str, end: str):
print("finished", sym_dict[reqId])
def run_loop():
app.run()
app = IBapi()
app.connect('127.0.0.1', 7496, 123)
# you should wait for nextValidId instead of sleeping, what if it takes more than 1 second? #john: how do i do this?
time.sleep(5) #john: how do i do this? wait for nextValidId?
symbols = ['SPY','MSFT','GOOG','AAPL','QQQ','IWM','TSLA']
reqId = 1
sym_dict = {}
for sym in symbols:
contract = Contract()
contract.symbol = str(sym)
sym_dict[reqId] = sym
contract.secType = "STK"
contract.exchange = "SMART"
contract.currency = "USD"
#contract.primaryExchange = "ISLAND" # you may need this for msft
app.reqHistoricalData(reqId, contract, "", "1 D", "10 mins", "ADJUSTED_LAST", 1, 2, False, [])
reqId += 1
time.sleep(5)
df = pd.DataFrame(app.data, columns=['DateTime', 'ADJUSTED_LAST','Volume','sym'])
df['DateTime'] = pd.to_datetime(df['DateTime'],unit='s') #,unit='s')
df = df.set_index(['sym','DateTime']).sort_index()
print(df)
app.disconnect()
You just need to maintain a dict of reqId and symbol.
I'm not sure that one DataFrame is the best way to store your data but if you do then set a multi index. Decide how much data you want and how you're going to store it on disk and then decide on a data structure. I suggest csv for speed or sqlite for simplicity. Pandas can handle either.
I deleted your comments and added some of my own.
from ibapi.client import EClient
from ibapi.wrapper import EWrapper
from ibapi.contract import Contract
import pandas as pd
import threading
import time
from datetime import timedelta
import datetime
# I added this code to get fake data, works wtihout tws running
from ibapi.common import BarData
from random import random
start = datetime.datetime.utcnow()
def fake_data(reqId, ib):
last = reqId*10
for i in range(60, 0, -10):
bar = BarData();
bar.date = start - timedelta(minutes=i)
last += random() - 0.5
bar.close = last
bar.volume = reqId * 1000
ib.historicalData(reqId, bar)
ib.historicalDataEnd(reqId,"","")
class IBapi(EWrapper, EClient):
def __init__(self):
EClient.__init__(self, self)
self.data = []
#always include this for important messages, also turn on api logging in TWS/IBG
def error(self, reqId, errorCode, errorString):
print("Error. Id: " , reqId, " Code: " , errorCode , " Msg: " , errorString)
def historicalData(self, reqId, bar):
self.data.append([bar.date, bar.close, bar.volume, sym_dict[reqId]])
# include this callback to track progress and maybe disconnectwhen all are finished
def historicalDataEnd(self, reqId: int, start: str, end: str):
print("finished", sym_dict[reqId])
def run_loop():
app.run()
app = IBapi()
app.connect('127.0.0.1', 7496, 123)
# threading is needed only if you plan to interact after run is called
# this is a good way if you use a ui like jupyter
api_thread = threading.Thread(target=run_loop, daemon=True)
api_thread.start()
# you should wait for nextValidId instead of sleeping, what if it takes more than 1 second?
time.sleep(1)
symbols = ['SPY','MSFT','GOOG','AAPL','QQQ','IWM','TSLA']
reqId = 1
sym_dict = {}
for sym in symbols:
contract = Contract()
contract.symbol = str(sym)
sym_dict[reqId] = sym
contract.secType = "STK"
contract.exchange = "SMART"
contract.currency = "USD"
#contract.primaryExchange = "ISLAND" # you may need this for msft
#app.reqHistoricalData(reqId, contract, "", "1 D", "10 mins", "ADJUSTED_LAST", 1, 2, False, [])
fake_data(reqId, app)
reqId += 1
#now you need to sleep(10) to make sure you don't get a pacing error for too many requests
# don't sleep, use historicalDataEnd to know when finished
time.sleep(5)
df = pd.DataFrame(app.data, columns=['DateTime', 'ADJUSTED_LAST','Volume','sym'])
df['DateTime'] = pd.to_datetime(df['DateTime'],unit='s')
#make an index and sort
df = df.set_index(['sym','DateTime']).sort_index()
# now you can use the indexes
print(df.loc[("SPY","2021")])
#don't forget to disconnect somewhere or the clientId will still be in use
I am trying to use IBpy to return historical data from some instruments, but when I try the code in the documentation I get an empty result.
I managed to make it work using R Ibroker but I would really prefer to have it working using the Python API.
Here is the code I am testing.
from time import sleep, strftime
from time import sleep
from ib.ext.Contract import Contract
from ib.opt import ibConnection, message
def my_account_handler(msg):
print(msg)
def my_tick_handler(msg):
print(msg)
if __name__ == '__main__':
con = ibConnection()
con.register(my_account_handler, 'UpdateAccountValue')
con.register(my_tick_handler, message.tickSize, message.tickPrice)
con.connect()
def inner():
qqqq = Contract()
qqqq.m_secType = "CASH"
qqqq.m_symbol = "MSFT"
qqqq.m_currency = "USD"
qqqq.m_exchange = "IDEALPRO"
endtime = strftime('%Y%m%d %H:%M:%S')
con.reqHistoricalData(1,qqqq,endtime,"5 D","1 hour","MIDPOINT",1,1)
sleep(10)
inner()
sleep(5)
print('disconnected', con.disconnect())
Any idea what might be going wrong?
You need to register for the historical data message.
con.register(my_hist_data_handler, message.historicalData)
Then define whatever you want to do with it
def my_hist_data_handler(msg):
print(msg)
Also note MSFT (or QQQ) is a stock
qqqq.m_secType = "STK" #cash is for forex
qqqq.m_symbol = "MSFT" #use less confusing var name
qqqq.m_currency = "USD"
qqqq.m_exchange = "SMART" #for stocks usually