#python #dictionary #chart.js
#питон #словарь #chart.js
Вопрос:
Я запрашиваю исторические данные о запасах из API. Конечная цель состоит в том, чтобы показать эти данные с помощью Chart.js. Возможно, что будет показано более одной цены акций. В любом случае я хочу нормализовать данные о ценах на акции (т. Е. Первая точка данных установлена на 100, следующие данные пересчитываются по первым точкам данных), которые показаны на графике. Однако во всплывающей подсказке должны быть указаны исходные данные. Поскольку может случиться так, что мне придется объединить акции, которые торгуются в разных регионах, может случиться так, что в определенные дни одна или несколько торговых площадок будут закрыты, и поэтому в эти дни не будет точки данных. В этом случае я действительно хочу заполнить эти недостающие точки данных той, которая была до этой даты.
В моем текущем решении я предоставляю chart.js с двумя наборами данных:
- Список списков, содержащих исходные данные о ценах (A)
- Список диктов, содержащих нормализованные данные (B)
Наборы данных выглядят следующим образом:
A:
[[25, 27, 29], [150, 175, 160], [50, 52, 54]]
B:
[ {'symbol': 'AAPL', 'historical': [{'date': '2021-11-30', 'close': '100'}, {'date': '2021-12-01', 'close': '108'}, {'date': '2021-12-02', 'close': '116'}]}, {'symbol': 'JNJ', 'historical': [{'date': '2021-11-30', 'close': '100'}, {'date': '2021-12-01', 'close': '116.66'}, {'date': '2021-12-02', 'close': '106.66'}]}, {'symbol': 'IBM', 'historical': [{'date': '2021-11-30', 'close': '100'}, {'date': '2021-12-01', 'close': '104'}, {'date': '2021-12-02', 'close': '108'}]}, ]
Чтобы получить данные в этом формате, я вызываю API для каждой акции (не могу запросить несколько символов одновременно), который затем возвращает json в следующем формате: [{'date': '2021-12-02', 'close': '29'}, {'date': '2021-12-01', 'close': '27'}, {'date': '2021-11-30', 'close': '25'}]
(как вы можете видеть, порядок изменен).
Это до сих пор прекрасно работает с Chart.js (Я выполняю обратный вызов для каждой точки данных, чтобы показать исходную цену из списка A).
Мой вопрос в том, могу ли я оптимизировать код для фактического создания этих двух наборов данных. Пожалуйста, найдите мой код ниже:
def get_chart_data(symbols, from_date=None, to_date=None): stock_data_complete = False for symb in symbol: # API call (returns empty list if no data found) h_prices = historical_price_full(symb, series_type='line', from_date=from_date, to_date=to_date) if h_prices: norm_data, real_data = _normalise_historical_data(h_prices, normalise=True) else: norm_data, real_data = [], [] norm_stock_prices.append({'symbol': symb, 'historical': norm_data}) real_stock_prices.append(real_data) if all(stock['historical'] for stock in norm_stock_prices): stock_data_complete = True # make sure, that all timeseries contain the same dates, otherwise add date with value '' # get all historical dates into an dictionary all_dates = {} for stock_history in norm_stock_prices: all_dates.update({stock_history['symbol']: list(map(lambda d: d['date'], stock_history['historical']))}) # generate list with all unique dates unique_dates = [] for symbol, dates in all_dates.items(): unique_dates.extend(dates) unique_dates = list(set(unique_dates)) # loop through all all dates for each stock and check if date is in unique dates. if not, add # datapoint to dict. missing_data_found = False for symbol, dates in all_dates.items(): for date in unique_dates: if date not in dates: for stock in norm_stock_prices: if stock['symbol'] == symbol: stock['historical'].append({'date': date}) missing_data_found = True break if missing_data_found: for i, stock in enumerate(norm_stock_prices): stock['historical'].sort(key=lambda item: item['date'], reverse=False) for j, value in enumerate(stock['historical']): if 'close' not in value: if j == 0: # Edge Case should the first data point be missing stock['historical'][j].update({'close': stock['historical'][j 1]['close']}) real_stock_prices[i].insert(j, stock['historical'][j 1]['close']) else: stock['historical'][j].update({'close': stock['historical'][j - 1]['close']}) real_stock_prices[i].insert(j, stock['historical'][j - 1]['close']) return norm_stock_prices, real_stock_prices, stock_data_complete def _normalise_historical_data(data, normalise: bool = False): data.sort(key=lambda item: item['date'], reverse=False) real_data = [] for datapoint in data: real_data.append(datapoint['close']) if normalise: norm_data = deepcopy(data) denominator = norm_data[0]['close'] for datapoint in norm_data: datapoint['close'] = datapoint['close'] / denominator * 100 else: norm_data = data return norm_data, real_data
This code works so far but it feels super hacky. Is there a better way to achieve the same results in a more pythonic way or even a better solution in combination with Chart.js?