to start I am very new to python (and coding period) so I apologize if I am going about this the wrong way.
I am receiving these json messages from a websocket stream:
import websocket, json, dateutil.parser
import dateparser
import csv
import itertools
current_tick = None
dataframe = []
symbols = 'AAPL', 'FB', 'AMZN', 'NFLX'
def on_open(ws):
print("opened")
auth_data = {
"action": "auth",
"params": 'APIKEY'
}
ws.send(json.dumps(auth_data))
for s in symbols:
channel_data = {
"action": "subscribe",
"params": s
}
ws.send(json.dumps(channel_data))
def on_message(ws, message):
global current_tick, dataframe
current_tick = json.loads(message)
print(current_tick)
if current_tick[0]['ev'] == 'T':
dataframe.append(current_tick)
def on_close(ws):
print("closed connection")
socket = "WEBSITE"
ws = websocket.WebSocketApp(socket, on_open=on_open, on_message=on_message, on_close=on_close)
#ws.run_forever()
OUTPUTS:
[{'ev': 'T', 'sym': 'AAPL', 'i': '227161', 'x': 4, 'p': 134.605, 's': 100, 't': 1609275343055, 'z': 3}]
[{'ev': 'T', 'sym': 'AAPL', 'i': '227162', 'x': 4, 'p': 134.605, 's': 3, 'c': [37], 't': 1609275343072, 'z': 3}]
[{'ev': 'T', 'sym': 'AAPL', 'i': '155273', 'x': 12, 'p': 134.6, 's': 25, 'c': [14, 37, 41], 't': 1609275343104, 'z': 3}]
[{'ev': 'T', 'sym': 'FB', 'i': '47501', 'x': 4, 'p': 276.5, 's': 1, 'c': [12, 37], 't': 1609276352067, 'z': 3}]
[{'ev': 'T', 'sym': 'NFLX', 'i': '10420', 'x': 11, 'p': 531.5, 's': 147, 'c': [14, 12, 41], 't': 1609276352376, 'z': 3}]
My goal is to to store these into SQL database as they come in, this is what I have so far
import psycopg2
postgresConnection = psycopg2.connect(
host='HOST',
user='USER',
password='PASSWORD',
database='DATABASE'
cursor= postgresConnection.cursor()
sqlCreateTable = "create table datas(sym varchar(256), price int, size int, exchange int, time int);"
cursor.execute(sqlCreateTable)
postgresConnection.commit()
sqlpoptable = "intert into datas(sym, price, size) VALUES(%(sym)s, %(price)s, %(size)s)", {"sym":current_tick['sym'],"price":current_tick['p'], "size":current_tick['s']}
cursor.execute(sqlpoptable)
postgresConnection.commit()
And my output is:
TypeError: list indices must be integers or slices, not str
Any thoughts? Thanks in advance.
As you may already know, you can access array data using an index. An index is a number that represents the data's position in the array, starting with the number zero.
If you have an array of items like this:
items = ['a', 'z', 'c', 'd']
Then the index of 'a' would be 0, the index of 'z' would be 1, the index of 'c' would be 2, and so on.
If you wrote some Python code that looked like this:
items = ['a', 'z', 'c', 'd']
myChosenItem = items[0]
Then myChosenItem would be equal to 'a'. Make sense?
The error you are getting is telling you that you tried to provide something other than an integer (a whole number) as an index when getting data out of an array.
That would be like writing this:
items = ['a', 'z', 'c', 'd']
myChosenItem = items['chicken']
Python would have no idea what you meant. Look at your code and figure out where you are accessing array data using an index, and then figure out if that index is an integer or not. Then you should be able to get this error to go away.
Related
I have a variable which stores below dictionary
initial_ltp =
{'s': 'ok',
'd': [{'n': 'MCX:CRUDEOIL23JANFUT',
's': 'ok',
'v': {'ch': 47.0,
'chp': 0.74,
'lp': 6377.0,
'spread': 2.0,
'ask': 6379.0,
'bid': 6377.0,
'open_price': 6330.0,
'high_price': 6393.0,
'low_price': 6305.0,
'prev_close_price': 6330.0,
'volume': 8410,
'short_name': 'CRUDEOIL23JANFUT',
'exchange': 'MCX',
'description': 'MCX:CRUDEOIL23JANFUT',
'original_name': 'MCX:CRUDEOIL23JANFUT',
'symbol': 'MCX:CRUDEOIL23JANFUT',
'fyToken': '1120230119244999',
'tt': 1673481600,
'cmd': {'t': 1673518200,
'o': 6376.0,
'h': 6378.0,
'l': 6375.0,
'c': 6377.0,
'v': 19,
'tf': '15:40'}}},
{'n': 'MCX:SILVERMIC23FEBFUT',
's': 'ok',
'v': {'ch': 485.0,
'chp': 0.71,
'lp': 68543.0,
'spread': 5.0,
'ask': 68545.0,
'bid': 68540.0,
'open_price': 68200.0,
'high_price': 68689.0,
'low_price': 68200.0,
'prev_close_price': 68058.0,
'volume': 49595,
'short_name': 'SILVERMIC23FEBFUT',
'exchange': 'MCX',
'description': 'MCX:SILVERMIC23FEBFUT',
'original_name': 'MCX:SILVERMIC23FEBFUT',
'symbol': 'MCX:SILVERMIC23FEBFUT',
'fyToken': '1120230228242738',
'tt': 1673481600,
'cmd': {'t': 1673518200,
'o': 68525.0,
'h': 68543.0,
'l': 68524.0,
'c': 68543.0,
'v': 140,
'tf': '15:40'}}}]}
I am trying to collect ('n') and ('lp') and save it in a different dictionary using code:
if 'd' in initial_ltp.keys():
ltp[initial_ltp['d'][0]['n']] = initial_ltp['d'][0]['v']['lp']
But it is only taking the first n and lp
ltp
{'MCX:CRUDEOIL23JANFUT': 6377.0}
My expected output:
ltp
{'MCX:CRUDEOIL23JANFUT': 6377.0, 'MCX:SILVERMIC23FEBFUT': 68543.0}
How can I get both the values
You have to loop over the list. Using ltp[initial_ltp['d'][0] will just extract for the first element of the list.
Here is an example:
results = {}
for doc in initial_ltp["d"]:
results[doc["n"]] = doc["v"]["lp"]
print(results)
Use the following approach with dict comprehension:
ltp = {d['n']:d['v']['lp'] for d in initial_ltp['d']} if 'd' in initial_ltp else {}
{'MCX:CRUDEOIL23JANFUT': 6377.0, 'MCX:SILVERMIC23FEBFUT': 68543.0}
when you use the "=" operator, it replaces your value in the dictionary key.
you want to add keys to your dictionary so I suggest using this:
if 'd' in initial_ltp.keys():
for o in initial_ltp['d']:
if n in o:
ltp[initial_ltp['d'][0]['n']].append(initial_ltp['d'][0]['v']
['lp']
It's because you selected only first item in the 'd'.
try a loop like this:
ltp={}
if 'd' in initial_ltp.keys():
for i in range(len(initial_ltp['d'])):
ltp[initial_ltp['d'][i]['n']] = initial_ltp['d'][i]['v']['lp']
print (ltp)
Output:
{'MCX:CRUDEOIL23JANFUT': 6377.0, 'MCX:SILVERMIC23FEBFUT': 68543.0}
Am getting API response Like Below
https://imgur.com/a/uVcLfF4
{'s': 'ok', 'd':
[
{'n': 'NSE:SBIN22JUL485CE', 's': 'ok', 'v': {'ch': -2.25, 'chp': -17.05, 'lp': 10.95, 'spread': 0.25, 'ask': 10.95, 'bid': 10.7, 'open_price': 11.5, 'high_price': 15.05, 'low_price': 10.45, 'prev_close_price': 13.2, 'volume': 1161000, 'short_name': 'SBIN22JUL485CE', 'exchange': 'NSE', 'description': 'NSE:SBIN22JUL485CE', 'original_name': 'NSE:SBIN22JUL485CE', 'symbol': 'NSE:SBIN22JUL485CE', 'fyToken': '1011220728149794', 'tt': 1657584000, 'cmd': {'t': 1657620000, 'o': 10.95, 'h': 10.95, 'l': 10.95, 'c': 10.95, 'v': 1500, 'tf': '15:30'}}
},
{'n': 'NSE:SBIN22JUL480CE', 's': 'ok', 'v': {'ch': -2.65, 'chp': -16.46, 'lp': 13.45, 'spread': 0.1, 'ask':
13.45, 'bid': 13.35, 'open_price': 15.3, 'high_price': 18.45, 'low_price': 12.9, 'prev_close_price': 16.1, 'volume': 4270500, 'short_name': 'SBIN22JUL480CE', 'exchange': 'NSE', 'description': 'NSE:SBIN22JUL480CE', 'original_name': 'NSE:SBIN22JUL480CE', 'symbol': 'NSE:SBIN22JUL480CE', 'fyToken': '1011220728128799', 'tt': 1657584000, 'cmd': {'t': 1657619940, 'o': 13.45, 'h': 13.45, 'l': 13.45, 'c': 13.45, 'v': 28500, 'tf': '15:29'}}
}
]
}
How to read and print this in python like below.
Name= NSE:SBIN22JUL485CE
ch = -2.25
chp = -17.05
volume = 1161000
Name= NSE:SBIN22JUL480CE
ch = -2.65
chp = -16.46
volume = 4270500
It looks like json, if you have that text in a variable, you can use the python json librarie for decoding it, and get a dictionary.
import json
text = '...' # The variable that contains the response
data = json.loads(text)
for entry in data['d']:
print(f'Name = {entry["n"]}')
print(f'ch = {entry["v"]["ch"]}')
print(f'chp = {entry["v"]["chp"]}')
print(f'volume = {entry["v"]["volume"]}')
print('')
If for some reason, in the text, the quotes are single quotes ' insted of double ", you should need to replace it, before the json parsing:
text = text.replace("'", '"')
If it is already a dict, just print the content:
mydict = <API response>
if 's' in mydict and mydict['s'] == 'ok':
for data in mydict['d']:
print('Name:', data['n'])
print('ch:', data['v']['ch'])
print('chp:', data['v']['chp'])
print('volume:', data['v']['volume'])
print()
If it is not a dict then you need to convert the content before:
import json
content = <API response>
mydict = json.loads(content)
<code to print above>
I have a dictionary that looks like:
my_dict = {
'A': 'update_me',
'B': {
'C': 'D',
'E': 'F'
},
'G': {
'H': 'update_me',
'I': 'J',
'K': 'update_me'
}
}
I'm trying to create a function that will loop through every key value pair and determine if that value is update_me. If it is, it will set that value equal to this_worked. So it'd look like this:
my_dict = {
'A': 'this_worked',
'B': {
'C': 'D',
'E': 'F'
},
'G': {
'H': 'this_worked',
'I': 'J',
'K': 'this_worked'
}
}
In addition to this, I would like this to be dynamic, so that the code doesn't have to explicitly look for my_dict['A'] or my_dict['G']['H']. It should just loop through each key value pair, and if that value is update_me, then update it (I have other dictionaries that I need to update in a similar way, but their keys, lengths and depths are varying).
I think I really just need a way to loop through every level of a dictionary that has any number of particular levels.
An easy way to handle operations with arbitrary levels of nesting is a recursive function. In this case, you want to perform an operation on each item in a dictionary, and do that same thing for each item that is itself a dictionary:
>>> def recursive_replace(d, old, new):
... if d == old:
... return new
... if not isinstance(d, dict):
... return d
... return {k: recursive_replace(v, old, new) for k, v in d.items()}
...
>>> recursive_replace(my_dict, "update_me", "this_worked")
{'A': 'this_worked', 'B': {'C': 'D', 'E': 'F'}, 'G': {'H': 'this_worked', 'I': 'J', 'K': 'this_worked'}}
A solution could be:
def replace(my_dict, old_test="update_me", new_text="this_worked"):
for x, y in my_dict.items():
if type(y) is dict:
replace(y)
elif type(y) is str:
if y == old_text:
y = new_text
my_dict[x] = y
return my_dict
You can achieve this by this
my_dict = {
'A': 'update_me',
'B': {
'C': 'D',
'E': 'F'
},
'G': {
'H': 'update_me',
'I': 'J',
'K': 'update_me'
}
}
old_value = "update_me"
new_value = "new_value"
def replace_value(my_dict, old_value, new_value):
for key, value in my_dict.items():
if type(value) is dict:
replace_value(value, old_value, new_value)
elif value == old_value:
my_dict[key] = new_value
return my_dict
my_dict = replace_value(my_dict, old_value, new_value)
print(my_dict)
# {'A': 'new_value', 'B': {'C': 'D', 'E': 'F'}, 'G': {'H': 'new_value', 'I': 'J', 'K': 'new_value'}}
I am using a third party python library, which returns some data in lists and dictionaries inside them (JSON format). For example, here's a sample entry:
data = [{'a': 1, 'b': 80, 'c': 42, 'd': [{'r': 0, 's': '1', 'u': 5}], 'id': 10, 'k': 60, 'v': 0, 'm':
{'ty': 'djp', 'nr': '10', 'bc': Adder('179'), 'in': 3}}, {'a': 1, 'b': 70, 'c': 42, 'd': [{'r': 0, 's':
'1', 'u': 5}], 'y': 10, 'k': 60, 'v': 0, 'm': {'ty': 'djp', 'dx': '10', 'tx': Adder('179'), 'in': 3}}]
My problem is with 'Adder' class which is an object. Everything else are just strings.
So, when I do:
json.dumps(data)
It causes an error message:
Adder('179') is not JSON serializable.
I don't care about serializing this Adder class, so I would somehow like to just make it a string e.g. "Adder(179)" if possible. Is it possible to make the dumps function work? Class Adder is not my own, maybe I can make it serialized or tell it what to do with it by editing the source or something? Any simple way would be fine.
Just specify a custom encoder class:
class RobustEncoder(json.JSONEncoder):
def default(self, o):
try:
return super(RobustEncoder, self).default(o)
except TypeError:
return str(o)
json.dumps(data, cls=RobustEncoder)
The keyword argument cls is documented in the docs of json.dump.
I'm trying to write a simple function that given a letter, you are returned the value of the scrabble tile. Here is what I have:
def letterPoint(letter):
letter = letter.upper()
lettersWorthOne =(['A','E','I','N','O','R','S','T'])
lettersWorthTwo = (['D','G'])
lettersWorthThree = (['B','C','M','P'])
lettersWorthFour = (['F','H','U','V','W','Y'])
lettersWorthFive = (['K'])
lettersWorthEight = (['J','X'])
lettersWorthTen = (['Q','Z'])
if letterWorthOne:
print '1'
if letterWorthTwo:
print '2'
if letterWorthThree:
print '3'
if letterWorthFour:
print '4'
if letterWorthFive:
print '5'
if letterWorthEight:
print '8'
if letterWorthTen:
print '10'
Use a dictionary. Rather than
lettersWorthTwo = (['D','G']), etc.
You would have a data structure along the lines of:
letterValues = {'D':2, 'G':2, ... }
Then a lookup for value is simply:
letterValues['D'] # returns 2 for the value of the tile
To point out why your code doesn't work, because you're not comparing your letter to the list.
#Change from this:
if letterWorthOne:
print '1'
#to this, should work
if letter in letterWorthOne:
print '1'
.....
Use a python dictionary is the way to go.
Further to the solution someone has already posted. You can also construct a more content dictionary like this:
Letters = {
'a': { 'quantity' : 9, 'value': 1},
'b': { 'quantity' : 2, 'value': 3},
'c': { 'quantity' : 2, 'value': 3},
'd': { 'quantity' : 4, 'value': 2},
'e': { 'quantity' : 12, 'value': 1},
'f': { 'quantity' : 2, 'value': 4},
'g': { 'quantity' : 3, 'value': 2},
'h': { 'quantity' : 2, 'value': 4},
'i': { 'quantity' : 9, 'value': 1},
'j': { 'quantity' : 1, 'value': 8},
'k': { 'quantity' : 1, 'value': 5},
'l': { 'quantity' : 4, 'value': 1},
'm': { 'quantity' : 2, 'value': 3},
'n': { 'quantity' : 6, 'value': 1},
'o': { 'quantity' : 8, 'value': 1},
'p': { 'quantity' : 2, 'value': 3},
'q': { 'quantity' : 1, 'value': 10},
'r': { 'quantity' : 6, 'value': 1},
's': { 'quantity' : 4, 'value': 1},
't': { 'quantity' : 6, 'value': 1},
'u': { 'quantity' : 4, 'value': 1},
'v': { 'quantity' : 2, 'value': 4},
'w': { 'quantity' : 2, 'value': 4},
'x': { 'quantity' : 1, 'value': 8},
'y': { 'quantity' : 2, 'value': 4},
'z': { 'quantity' : 1, 'value': 10},
'*': { 'quantity' : 2, 'value': 0}
}
# to get to it's "content", like this:
Letters['a']
{'quantity': 9, 'value': 1}
# you can then get its 'value' or 'quantity' in a tile bag
Letters['a']['value']
1
# if you MUST use a function, do this with above dictionary, although it's quite pointless
def letter_point(letter):
return Letters[letter.upper()]['value']
In letterPoint(), letterWorthOne and lettersWorthOne are separate variables. Each lettersWorth* variable holds a list, and you appear to want letterWorthOne to contain a boolean value (True or False) specifying whether or not letter is in the lettersWorthOne list. To determine whether a value is in a collection, use operator in.
def letterPoint(letter):
letter = letter.upper()
lettersWorthOne =(['A','E','I','N','O','R','S','T'])
lettersWorthTwo = (['D','G'])
letterWorthOne = letter in lettersWorthOne
if letterWorthOne:
print '1'
letterWorthTwo = letter in lettersWorthTwo
if letterWorthTwo:
print '2'
# rest of values omitted for brevity
print 'E worth'
letterPoint('E')
print 'D worth'
letterPoint('D')
This program produces the following output:
E worth
1
D worth
2
This explains why your existing function doesn't work. But in the long run, I'd recommend using a dictionary to hold the value and quantity of each letter, and store the values as numbers instead of strings so that you can add the values of all letters in a word.
To use the code you began with, you could consider changing the lines to:
if letter in lettersWorthOne print 1
...
This is because the data structure you're using is a list (it is surrounded by [] brackets). The way to use these lists in your function is to see if they contain the letter in the list using the code:
if <variable> in <list> print <value>
The () brackets aren't doing anything, as mentioned in another answer so you can get rid of them.
This is just to explain to you why you don't see any result in the function you've written. The other answers which suggest using a dict (dictionary) are a better approach in practice.