jeninja
jeninja

Reputation: 848

Python JSON Serialize Dictionary<String,Object>

I have a Dictionary with Key String (2019-10-28 13:21) and Value of Object (DataPoint)

import requests
import json
import time

symbol = "AAPL"

intraday_url = "https://www.alphavantage.co/query?function=TIME_SERIES_INTRADAY&symbol="+symbol+"&interval=1min&outputsize=full&apikey="+api_key
sma_url = "https://www.alphavantage.co/query?function=SMA&symbol="+symbol+"&interval=1min&time_period=180&series_type=open&apikey="+api_key
ema_url = "https://www.alphavantage.co/query?function=EMA&symbol="+symbol+"&interval=1min&time_period=15&series_type=open&apikey="+api_key
vwap_url = "https://www.alphavantage.co/query?function=VWAP&symbol="+symbol+"&interval=1min&apikey="+api_key
macd_url = "https://www.alphavantage.co/query?function=MACD&symbol="+symbol+"&interval=1min&series_type=open&apikey="+api_key
rsi_url = "https://www.alphavantage.co/query?function=RSI&symbol="+symbol+"&interval=1min&time_period=100&series_type=open&apikey="+api_key
adx_url = "https://www.alphavantage.co/query?function=ADX&symbol="+symbol+"&interval=1min&time_period=100&apikey="+api_key

class DataPoint:
    def __init__(self, time):
        # 2019-10-31 15:49:00 (original)
        # 2019-10-31 15:49 (formatted)
        formatted_time = time[0:len(time)-3]
        self.time = formatted_time
        self.open = None
        self.high = None
        self.low = None
        self.close = None
        self.volume = None
        self.sma = None
        self.ema = None
        self.vwap = None
        self.macd = None
        self.rsi = None
        self.adx = None

    def addIntraday(self,open,high,low,close,volume):
        self.open = open
        self.high = high
        self.low = low
        self.close = close
        self.volume = volume

    def addTechnical(self,technical,value):
        if technical == "SMA":
            self.sma = value
        elif technical == "EMA":
            self.ema = value
        elif technical == "VWAP":
            self.vwap = value
        elif technical == "MACD":
            self.macd = value
        elif technical == "RSI":
            self.rsi = value
        elif technical == "ADX":
            self.adx = value

def getIntraday(dictionary):
    url = intraday_url
    response = requests.get(url)
    json = response.json()
    intraday = json.get("Time Series (1min)")
    keys = intraday.keys()
    for key in keys:
        ts = intraday.get(key)
        dp = DataPoint(key)
        open = ts.get("1. open")
        high = ts.get("2. high")
        low = ts.get("3. low")
        close = ts.get("4. close")
        volume = ts.get("5. volume")
        dp.addIntraday(open,high,low,close,volume)
        dictionary[dp.time] = dp

def getTechnicals(dictionary):
    urls = [sma_url, ema_url, vwap_url, macd_url, rsi_url, adx_url]
    technicals = ["SMA","EMA","VWAP","MACD","RSI","ADX"]
    i = 0
    while (i < len(urls)):
        response = requests.get(urls[i])
        json = response.json()
        tech = json.get("Technical Analysis: " + technicals[i])
        if (tech == None):
            print("Empty response, retrying in 10 seconds...")
            time.sleep(10)
        else:
            print("Getting Technical Indicator: " + technicals[i])
            keys = tech.keys()
            for key in keys:
                t = tech.get(key)
                v = t.get(technicals[i])
                if (dictionary.get(key) != None):
                    dictionary.get(key).addTechnical(technicals[i], v)
            i += 1

def writeDictionaryToFile(dictionary):
    filename = "datapoints.json"
    fp = open(filename, "a")
    json_dictionary = json.dumps(dictionary)
    fp.write(json_dictionary)
    print("Wrote results to file: " + filename)

dictionary = {}

getIntraday(dictionary)

getTechnicals(dictionary)

writeDictionaryToFile(dictionary)

Here is the error:

Traceback (most recent call last):
  File "/Users/Jason/Dev/Python/neural-network-example/alphavantage.py", line 124, in <module>
    writeDictionaryToFile(dictionary)
  File "/Users/Jason/Dev/Python/neural-network-example/alphavantage.py", line 113, in writeDictionaryToFile
    json_dictionary = json.dumps(dictionary)
  File "/usr/local/Cellar/python/3.7.4_1/Frameworks/Python.framework/Versions/3.7/lib/python3.7/json/__init__.py", line 231, in dumps
    return _default_encoder.encode(obj)
  File "/usr/local/Cellar/python/3.7.4_1/Frameworks/Python.framework/Versions/3.7/lib/python3.7/json/encoder.py", line 199, in encode
    chunks = self.iterencode(o, _one_shot=True)
  File "/usr/local/Cellar/python/3.7.4_1/Frameworks/Python.framework/Versions/3.7/lib/python3.7/json/encoder.py", line 257, in iterencode
    return _iterencode(o, 0)
  File "/usr/local/Cellar/python/3.7.4_1/Frameworks/Python.framework/Versions/3.7/lib/python3.7/json/encoder.py", line 179, in default
    raise TypeError(f'Object of type {o.__class__.__name__} '
TypeError: Object of type DataPoint is not JSON serializable

From my understanding, I can use json.dumps() on a common python datatype, string, int, array dictionary, etc. But I cannot use it on custom objects that I've created. I've done research and from my research, I have figured out to use myCustomObject.dict to make the object serializable. How can I use this when I am trying to serialize the entire dictionary?

I'm new to Python, I just can't figure this out. Any help is greatly appreciated.

Upvotes: 0

Views: 2164

Answers (2)

kaya3
kaya3

Reputation: 51034

It's possible to achieve this using a custom JSON serializer, but that may be overkill for your task. A simpler solution is to give your class a couple of methods to convert to JSON and back, via dictionaries.

Your class has quite a lot of fields, so I'll give a simpler example for a toy class, which you should be able to adapt for your purpose:

import json

class Example:
    def __init__(self, x, y):
        self.x = x
        self.y = y

    def to_json(self):
        return json.dumps({
            'x': self.x,
            'y': self.y
        })

    @classmethod
    def from_json(cls, s):
        d = json.loads(s)
        return cls(d['x'], d['y'])

Usage:

>>> ex = Example(1, 2)
>>> s = ex.to_json()
>>> s
'{"y": 2, "x": 1}'
>>> ex2 = Example.from_json(s)
>>> ex2.x
1
>>> ex2.y
2

Upvotes: 4

Gloweye
Gloweye

Reputation: 1428

json is a very portable format, but it's also restricted. Only the following things can be serialized with Json:

dicts - {} (all keys must be strings)
lists - []
strings - "string"
integers - 0, 1, 2, ...
True
False
None

So you'll have to transform your object to some combination of these things, and have code to transform it back.

If you are planning on ONLY using python, you may be interested in pickle, which can serialize arbitrary python objects, as long as it can import the modules in which they were defined. Do note that unpacking pickles from unknown sources can lead to remote code executions.

Upvotes: 2

Related Questions