Python multiple requests with single code - python

I am using the IB API to retrieve historical stock data, and I would like my code to run multiple times with different variables (different stocks and timeframes).
Currently I am using the following code:
from ibapi.client import EClient
from ibapi.wrapper import EWrapper
from ibapi.contract import Contract
def print_to_file(*args):
with open('text6.txt', 'a') as fh:
fh.write(' '.join(map(str,args)))
fh.write('\n')
print = print_to_file
class TestApp(EWrapper, EClient):
def __init__(self):
EClient.__init__(self, self)
Layout = "{!s:1} {!s:2} {!s:3} {!s:4} {!s:5} {!s:6} {!s:7} {!s:8} {!s:8} '\n'"
print(Layout.format("Ticker;", "Date;", "None;", "Time;", "Open;", "High;", "Low;", "Close;", "Volume"))
def historicalData(self, reqId, bar):
print("AAPL", ";", bar.date.replace(' ', '; '), ";", bar.open, ";", bar.high, ";", bar.low, ";", bar.close, ";", bar.volume)
def main():
app = TestApp()
app.connect("127.0.0.1", 7497, 0)
contract = Contract ()
contract.symbol = "AAPL"
contract.secType = "STK"
contract.exchange = "SMART"
contract.currency = "USD"
contract.primaryExchange = "NASDAQ"
app.reqHistoricalData(0, contract, "20180201 10:00:00", "1 M", "1 min", "TRADES", 0, 1, False, [])
app.run()
if __name__ == "__main__":
main()
I have tried the following for multiple stocks:
contract.symbol = ["AAPL", "GOOG"]
But this gives me the error message:
No security definition has been found for the request
And using the following code for time & date:
app.reqHistoricalData(0, contract, ["20180201 10:00:00", "20180301 10:00:00"], "1 M", "1 min", "TRADES", 0, 1, False, [])
Gives me the error message:
Error validating request:-'bP' : cause - Historical data query end date/time string [['20180201 10:00:00', '20180301 10:00:00']] is invalid. Format is 'YYYYMMDD{SPACE}hh:mm:ss[{SPACE}TMZ]'.
Basically I would like this .py file to run multiple requests in a single run, using multiple variables so that I can receive data for multiple stocks in a single run.
Could anybody here help me to achieve this?
Thanks!

You can create a class that derives from the Contract class in order to create multiple Contract objects at one time. Then, make a loop that passes your Contract objects into the client in order to get the data. What you are currently doing is pretty far off from any implementation that would actually work. Check out this blog for help with the set-up of a working system -> https://qoppac.blogspot.com/2017/03/interactive-brokers-native-python-api.html
As far as the contract class, look at the relevant parameters in the documentation and create a class as necessary. Here is an example of my futures class:
class IBFutures(Contract):
def __init__(self, symbol:str, exchange:str, secType:str,
currency = 'USD', localSymbol = ""):
Contract.__init__(self)
self.symbol = symbol
self.secType = secType
self.exchange = exchange
self.currency = currency
self.localSymbol = localSymbol
Then, in your client object, make a function similar to this:
def getHistoricalData(self, contracts, durationStr="3 D", barSizeSetting="30 mins", whatToShow = "TRADES"):
"""
Returns historical prices for a contract, up to today
ibcontract is a Contract
:returns list of prices in 4 tuples: Open high low close volume
"""
defaultid = 80
prices = {}
for symbol in contracts:
defaultid += 1 # update defaultid
# Make a place to store the data we're going to return
historic_data_queue = finishableQueue(self.init_historicprices(defaultid))
# Should endDateTime be set to 9:00AM EST??
# Request some historical data. Native method in EClient
self.reqHistoricalData(reqId=defaultid, contract = contracts[symbol],
endDateTime=datetime.datetime.today().strftime("%Y%m%d %H:%M:%S"),
durationStr=durationStr, barSizeSetting=barSizeSetting,
whatToShow=whatToShow, useRTH=0, formatDate=1,
keepUpToDate=False, chartOptions=[])
# Wait until we get a completed data, an error, or time-out
MAX_WAIT_SECONDS = 30
logger.info("Getting %s historical data from the server..." % symbol)
historic_data = historic_data_queue.get(timeout=MAX_WAIT_SECONDS)
clean_data = cleanPrice(data=historic_data)
prices[symbol] = clean_data
if historic_data_queue.timed_out():
logger.info("Exceeded maximum wait for wrapper to confirm finished")
self.cancelHistoricalData(defaultid)
logger.info("Prices retrieved for %d contracts" % len(prices))
return prices

Related

How do I append data in google sheet using python?

I am trying to download the data from IB api and upload it onto a google sheet. If the data already exists in the sheet, then I want the new data to be added into the sheet without overwriting the previous data. This is what I have done so far:
from ibapi.client import EClient
from ibapi.wrapper import EWrapper
from ibapi.contract import Contract
from threading import Timer
import pandas as pd
from datetime import datetime
import os
import pygsheets
class TestApp(EWrapper, EClient):
def __init__(self):
EClient.__init__(self, self)
self.df = pd.DataFrame(columns=['accountName', 'contract', 'position','marketPrice', 'marketValue', 'averageCost', 'unrealizedPNL','realizedPNL'])
self.df1 = pd.DataFrame(columns=['key', 'value', 'currency'])
def error(self, reqId, errorCode, errorString):
print("Error: ", reqId, " ", errorCode, " ", errorString)
def nextValidId(self,orderId):
self.start()
def updatePortfolio(self, contract: Contract, position: float, marketPrice: float, marketValue: float,
averageCost: float, unrealizedPNL: float, realizedPNL: float, accountName: str):
self.df.loc[len(self.df)] = [accountName, contract.symbol,position,marketPrice, marketValue,averageCost, unrealizedPNL,realizedPNL]
# See unrealized P&L, which will be the total unrealized P&L since the position was open, the
# realized P&L which would be the realized profit loss for the current day
# If you’ve closed out any positions, as well as the account name, the current market value,
# the average cost used to open the position and of course the position size
print("UpdatePortfolio.", "Symbol:", contract.symbol, "SecType:", contract.secType, "Exchange:",
contract.exchange,
"Position:", position, "MarketPrice:", marketPrice, "MarketValue:", marketValue, "AverageCost:",
averageCost,
"UnrealizedPNL:", unrealizedPNL, "RealizedPNL:", realizedPNL, "AccountName:", accountName)
def updateAccountValue(self, key: str, val: str, currency: str, accountName: str):
# returns the cash balance, the required margin for the account, or the net liquidity
self.df1.loc[len(self.df)] = ['ExchangeRate', val, currency]
print("UpdateAccountValue. Key:", key, "Value:", val, "Currency:", currency, "AccountName:", accountName)
def updateAccountTime(self, timeStamp: str):
print("UpdateAccountTime. Time:", timeStamp)
def accountDownloadEnd(self, accountName: str):
print("AccountDownloadEnd. Account:", accountName)
def start(self):
# ReqAccountUpdates - This function causes both position and account information to be returned for a specified account
# Invoke ReqAccountUpdates with true to start a subscription
self.reqAccountUpdates(True, "U0000000") # <----- Change account number here
def stop(self):
self.reqAccountUpdates(False,"U00000") # <----- Change account number here
self.done = True
self.disconnect()
def main():
app = TestApp()
app.connect("127.0.0.1", 7496, 0)
Timer(5, app.stop).start()
app.run()
# service file is the ib_data json file key
service_file_path = "googlesheet_api_json"
gc = pygsheets.authorize(service_file= service_file_path )
spreadsheet_id = '00000'
sh = gc.open_by_key(spreadsheet_id)
# inserting date and time to the data
now = datetime.now()
dt_string = now.strftime("%d/%m/%Y %H:%M:%S")
app.df['Date_Time'] = dt_string
#check if the google sheet has previous data
wk_sheet_stock = gc.open('workbook').sheet1
cells = wk_sheet_stock.get_all_values(include_tailing_empty_rows=False, include_tailing_empty=False, returnas='matrix')
if len(cells) < 1:
print('no data in the file')
data_write = sh.worksheet_by_title('stocks')
data_write.clear('A1',None,'*')
data_write.set_dataframe(app.df, (1,1), encoding='utf-8', fit=True)
data_write.frozen_rows = 1
data_write = sh.worksheet_by_title('currency')
data_write.clear('A1', None, '*')
data_write.set_dataframe(app.df1, (1, 1), encoding='utf-8', fit=True)
data_write.frozen_rows = 1
else:
print('adding data to the file')
stock_df_values = app.df.values.tolist()
currency_df_values = app.df1.values.tolist()
sh.values_append('stocks', {'valueInputOption': 'RAW'}, {'values': stock_df_values})
sh.values_append('currency', {'valueInputOption': 'RAW'}, {'values': currency_df_values})
if __name__ == "__main__":
main()
I get the error: AttributeError: 'Spreadsheet' object has no attribute 'values_append'
I am confused as to how do I go about this. Thank you for your help!
I believe your goal is as follows.
You want to append the values using values_append.
You want to remove your current issue of I get the error: AttributeError: 'Spreadsheet' object has no attribute 'values_append'.
You want to achieve this using pygsheets for python.
Modification points:
When I saw the document of pygsheets, it seems that the method of values_append is for class pygsheets.sheet.SheetAPIWrapper. In this case, sh of sh = gc.open_by_key(spreadsheet_id) is not it. I think that this might be the reason for your current issue of AttributeError: 'Spreadsheet' object has no attribute 'values_append'.
And, I cannot know your values of stock_df_values and currency_df_values. So, in this answer, I propose a modification point by guessing that those values are the 2-dimensional array. Please be careful about this.
When these points are reflected in your script, how about the following modification?
From:
sh.values_append('stocks', {'valueInputOption': 'RAW'}, {'values': stock_df_values})
sh.values_append('currency', {'valueInputOption': 'RAW'}, {'values': currency_df_values})
To:
gc.sheet.values_append(spreadsheet_id, stock_df_values, "ROWS", "stocks")
gc.sheet.values_append(spreadsheet_id, currency_df_values, "ROWS", "currency")
Note:
I guessed that the values of "stocks" and "currency" are the sheet names in the Spreadsheet of sh = gc.open_by_key(spreadsheet_id). Please be careful about this.
If you cannot know whether the values of stock_df_values and currency_df_values are a 2-dimensional array, please modify them as follows.
gc.sheet.values_append(spreadsheet_id, stock_df_values if isinstance(stock_df_values[0], list) else [stock_df_values], "ROWS", "stocks")
gc.sheet.values_append(spreadsheet_id, currency_df_values if isinstance(currency_df_values[0], list) else [currency_df_values], "ROWS", "currency")
In this answer, I suppose that other parts except for sh.values_append of your script work fine. Please be careful about this.
Reference:
values_append

Having Trouble Returning a value from a smart contract, using flask on python anywhere

I am using flask and web3.eth on pythonanywhere and connecting to a contract, but am having issues returning a value for one of the smart contract functions. No errors are being logged. I have placed several print statements to see where the app is stopping and found that it stops when I call a smart contract function.
Also I should mention that I am able to run this exact code locally without issues.
This is the function that is most likely failing:
def getDataFromTokenID(tokenid, contract):
print('getting uri')
uri = contract.functions.tokenURI(tokenid).call() # This is where it stops printing
print('PRINT:',uri)
html = requests.get(uri)
name, img_url = html.json()['name'], html.json()['image']
code = name[-5:]
return name, img_url, code
The function above is called in the following blueprint:
#TokenInfo.route('/rarity/<int:tokenid>', methods=['GET'])
def sendTokenInfo(tokenid):
contract_address = ' ' # left empty for posting purposes
w3 = Web3(Web3.WebsocketProvider(' ')) # left empty purposefully as well
contract = w3.eth.contract(address=contract_address, abi=contract_abi.abi)
model = Shape_classifier()
model.load_state_dict(load(os.getcwd()+'/mysite/app/state_dict.pth'))
uri = current_app.config['MONGO_URI']
mongo.init_app(current_app, uri)
gs = mongo.db.gantomstone_info
try:
id_exists = [{"$match": {'_id': tokenid}}, {"$count": "count"}]
list(gs.aggregate(id_exists))[0]
except:
print('getting data from token id')
name, img_url, serial = getDataFromTokenID(tokenid, contract) ## Stops printing here
print('opening image')
img = Image.open(requests.get(img_url, stream=True).raw)
shape = getImageShape(img, model)
colors = getColors(getCounts(img))
rgb_count = getCounts(img)
serialTF = getCodeInfo(serial)
to_db = {'_id': tokenid, 'name': name, 'img_url': img_url, 'serial': serial,
'shape': shape, 'colors': colors, 'serialTF': serialTF, 'rgb_count': rgb_count}
gs.insert_one(to_db)
rarity = getRarity(gs, tokenid)
gs.update_one({'_id': tokenid}, {
'$set': {'rarity_values': rarity}}, upsert=True)
to_json = list(gs.find({'_id': tokenid}))[0]
return jsonify(to_json)
I have tried moving contract address around (both out of TokenInfo view function and into the functions file) to no avail. I have also tried changing the function inputs to receive the get request args instead of the int in the URL, which made no difference either.
If the code uses websockets it won't currently work in web apps on PythonAnywhere.

How to use weatherstack.com api

Hi I'm pretty new to python. I try to make a chatbot with rasa for personal use. Would like to add weather api now. I use weatherstack.com. If I use their example this works, but if I adjust it to my own liking I always end up with the same error.
condition = api_response['current']['weather_descriptions'] TypeError: list indices must be integers or slices, not str
This is the code I am using.
class Actionweatherapi(Action):
def name(self):
return "actions.weatherapi"
def run(self, dispatcher, tracker, domain):
import requests
location = tracker.get_slot('location')
if location == 'None':
location = 'fetch:ip'
api_result = requests.get('http://api.weatherstack.com/current?access_key=0000000&query={}'.format(location))
api_response = api_result.json()
country = api_response['request']['query']
condition = api_response['current']['weather_descriptions']
temperature_c = api_response['current']['temperature']
humidity = api_response['current']['humidity']
wind_mph = api_response['current']['wind_speed']
response = """It is currently {} in {} at the moment. The temperature is {} degrees, the humidity is {}% and the wind speed is {} mph.""".format(condition, country, temperature_c, humidity, wind_mph)
dispatcher.utter_message(response)
return [AllSlotsReset()]
I have also reviewed the printf-style String Formatting on the python website, but I cannot figure out how to get it working.
The json response is like this example
http://api.weatherstack.com/current?access_key=1c80e8b9fe4fcef4f8d6fd7514a8e9e9&query=New%20York

Placing options order

I am new to python and programming but I am learning. I am trying to send an order through python for options to TWS. I keep getting this error message
"Server Error: Server Response:
error, Traceback (most recent
call last):"
I tried to put an order for stock and it went through but not for options
def create_contract(a,b,c,d):
contract = Contract()
contract.symbol = '%a'
contract.secType = "OPT"
contract.exchange = "SMART"
contract.order_exchange = "SMART"
contract.currency = "USD"
contract.ContractMonth = b
contract.strike = c
contract.right = '%d'
contract.multiplier = "100"
return contract
def create_order(order_type, quantity, action):
order = Order()
order.m_orderType = order_type
order.m_totalQuantity = quantity
order.m_action = action
return order
if __name__ == "__main__":
tws_conn = Connection.create("127.0.0.1", port=7495)
tws_conn.connect()
tws_conn.register(error_handler, 'Error')
tws_conn.registerAll(reply_handler)
order_id = 1
goog_contract = create_contract(tic,hup.cell(2,3).value,hup.cell(2,4).value,hup.cell(2,13).value)
goog_order = create_order('MKT', 1, 'BUY')
tws_conn.placeOrder(order_id, goog_contract, goog_order)
I want to see the option orders goes through TWS. I also would love to see some proper example on how the placeorder parameter should have.
from ib_insync import *
util.startLoop()
ib=IB()
ib.connect("127.0.0.1", 7497, clientId=13)
contract=Option("SPY","20191016", 280,"P","SMART")
ib.qualifyContracts(contract)
order=MarketOrder("Buy",2)
trade=ib.placeOrder(contract,order)
trade
this code will allow. you to buy 2 puts on the "spy" at a 280 strike expiring October 19 2019
It looks like you're using IBPy or a third party wrapper of an IB API? You may want to consider instead using the native Python API from IB, or ib_insync.
If you can place an order for a stock but not an option, the problem is likely in the way the option contract is defined (assuming your paper account has the necessary permissions). There are examples of defining options in the native IB Python API at:
http://interactivebrokers.github.io/tws-api/basic_contracts.html#opt
To say which parameter is incorrect you would have to show the values of a,b,c,d.
You may want to also enable API logging in TWS as described at:
http://interactivebrokers.github.io/tws-api/support.html#tws_logs
for troubleshooting purposes.

Deserializing JSON into python Class / Object

I am fairly new to python and need help taking a json file and incorporating
it into the init in a class to be used through out, but I am getting the error below and don't understand why. I have a build a few classes before and this seems to look the same.
AttributeError: 'dict' object has no attribute 'zipcode'
I have a separate json file called config.json that I have changed some information in (i.e. location and api key), but other than that, this is what I am working with.
config.json:
{
"unit_system":"metric",
"location_information":{
"country_code":"US",
"country_name":"United States",
"city":"New York City",
"state":"New York",
"postal":10001
},
"api_keys":{
"weather_api_key":"97a484e1039b7a0779b59f2e57e597a3"
}
}
weather.py
class weather:
"""weather retrieving app"""
def __init__(self, data):
"""initialize attributes for weather app"""
self.unit_system = data['unit_system']
#unit system
self.country_code = data['location_information']['country_code']
self.zipcode = data['location_information']['postal']
#location information
self.api_key = data['api_keys']['weather_api_key']
#api key informaation
def get_update(self):
threading.Timer(5.0, w.get_update).start()
#runs get_update every 5 seconds
#get weather information
weather_url = 'http://api.openweathermap.org/data/2.5/weather?zip=' \
+ str(self.zipcode) + ',' \
+ self.country_code + '&appid=' \
+ self.api_key
weather_request = requests.get(weather_url)
weather_data = weather_request.json()
temp_k = float(weather_data['main']['temp'])
#determine unit system conversions
if self.unit_system == 'english':
temp = (temp_k - 273.15) * 1.8 + 32
elif self.unit_system == 'metric':
temp = temp_k - 273.15
print(temp)
#return(temp)
import threading
import requests
import json
with open('config.json') as config_file:
config = json.load(config_file)
w = weather(config)
w.get_update()
Remove the last line and put these lines at the bottom. The first line creates an instance of class weather named weather_obj. You can then call the get_update using weather_obj
weather_obj = weather(config)
weather_obj.get_update()
The scipt you have provided seems to be working.
a screenshot of my output(s)

Categories