Как записывать обновляющийся словарь в CSV?
Есть словарь, который нужно записать в CSV.
Сам словарь:
{'custom': False, 'chart_mode': 1, 'select': True, 'visible': True, 'session_deals': 0, 'session_buy_orders': 0, 'session_sell_orders': 0, 'volume': 1, 'volumehigh': 16, 'volumelow': 1, 'time': 1608611959, 'digits': 2, 'spread': 1, 'spread_float': True, 'ticks_bookdepth': 32, 'trade_calc_mode': 33, 'trade_mode': 4, 'start_time': 0, 'expiration_time': 0, 'trade_stops_level': 0, 'trade_freeze_level': 0, 'trade_exemode': 2, 'swap_mode': 0, 'swap_rollover3days': 3, 'margin_hedged_use_leg': False, 'expiration_mode': 15, 'filling_mode': 3, 'order_mode': 127, 'order_gtc_mode': 0, 'option_mode': 0, 'option_right': 0, 'bid': 47.66, 'bidhigh': 47.87, 'bidlow': 47.59, 'ask': 47.67, 'askhigh': 47.88, 'asklow': 47.6, 'last': 47.67, 'lasthigh': 47.88, 'lastlow': 47.59, 'volume_real': 1.0, 'volumehigh_real': 16.0, 'volumelow_real': 1.0, 'option_strike': 0.0, 'point': 0.01, 'trade_tick_value': 10.0, 'trade_tick_value_profit': 10.0, 'trade_tick_value_loss': 10.0, 'trade_tick_size': 0.01, 'trade_contract_size': 1.0, 'trade_accrued_interest': 0.0, 'trade_face_value': 0.0, 'trade_liquidity_rate': 0.0, 'volume_min': 1.0, 'volume_max': 1000.0, 'volume_step': 1.0, 'volume_limit': 0.0, 'swap_long': 0.0, 'swap_short': 0.0, 'margin_initial': 1000.0, 'margin_maintenance': 1000.0, 'session_volume': 0.0, 'session_turnover': 0.0, 'session_interest': 0.0, 'session_buy_orders_volume': 0.0, 'session_sell_orders_volume': 0.0, 'session_open': 0.0, 'session_close': 0.0, 'session_aw': 0.0, 'session_price_settlement': 0.0, 'session_price_limit_min': 0.0, 'session_price_limit_max': 0.0, 'margin_hedged': 0.0, 'price_change': 0.0, 'price_volatility': 0.0, 'price_theoretical': 0.0, 'price_greeks_delta': 0.0, 'price_greeks_theta': 0.0, 'price_greeks_gamma': 0.0, 'price_greeks_vega': 0.0, 'price_greeks_rho': 0.0, 'price_greeks_omega': 0.0, 'price_sensitivity': 0.0, 'basis': 'CLE', 'category': '', 'currency_base': 'USD', 'currency_profit': 'USD', 'currency_margin': 'USD', 'bank': '', 'description': 'Crude Light (Globex)', 'exchange': '', 'formula': '', 'isin': '', 'name': '@CLE', 'page': '', 'path': 'Exchange-Futures\\@CLE'}
На выходе хочу получить таблицу, где ключи - это заголовок столбца, а значения - это строка столбца. При каждом запросе значения словаря меняются.
Как реализовать запись так, чтобы ключи были заголовками столбца, а значения строками, и далее, добавлять новые строки с теми же значениями ключей?
Ответы (3 шт):
Я реализовал простой класс CsvAdder, пример его использования ниже:
class CsvAdder:
def __init__(self, fname):
self.f = open(fname, 'w', encoding = 'utf-8')
self.w = None
def add(self, d):
if self.w is None:
import csv
self.w = csv.DictWriter(self.f, fieldnames = list(d.keys()))
self.w.writeheader()
self.w.writerow(d)
def close(self):
self.f.close()
def __enter__(self):
return self
def __exit__(self, t, v, tr):
self.close()
# Example of usage
# ----- Variant 1 -----
ca = CsvAdder('test.csv')
# Add first record
d = {'a': 1, 'b': 2}
ca.add(d)
# Later add second
d = {'a': 3, 'b': 4}
ca.add(d)
ca.close()
# ----- Variant 2 -----
with CsvAdder('test.csv') as ca:
# Add first record
d = {'a': 1, 'b': 2}
ca.add(d)
# Later add second
d = {'a': 3, 'b': 4}
ca.add(d)
Выходной файл:
a,b
1,2
3,4
воспользуйтесь модулем pandas:
import pandas as pd
import os
my_dict={'custom': False, 'chart_mode': 1, 'select': True, 'visible': True, 'session_deals': 0, 'session_buy_orders': 0, 'session_sell_orders': 0, 'volume': 1, 'volumehigh': 16, 'volumelow': 1, 'time': 1608611959, 'digits': 2, 'spread': 1, 'spread_float': True, 'ticks_bookdepth': 32, 'trade_calc_mode': 33, 'trade_mode': 4, 'start_time': 0, 'expiration_time': 0, 'trade_stops_level': 0, 'trade_freeze_level': 0, 'trade_exemode': 2, 'swap_mode': 0, 'swap_rollover3days': 3, 'margin_hedged_use_leg': False, 'expiration_mode': 15, 'filling_mode': 3, 'order_mode': 127, 'order_gtc_mode': 0, 'option_mode': 0, 'option_right': 0, 'bid': 47.66, 'bidhigh': 47.87, 'bidlow': 47.59, 'ask': 47.67, 'askhigh': 47.88, 'asklow': 47.6, 'last': 47.67, 'lasthigh': 47.88, 'lastlow': 47.59, 'volume_real': 1.0, 'volumehigh_real': 16.0, 'volumelow_real': 1.0, 'option_strike': 0.0, 'point': 0.01, 'trade_tick_value': 10.0, 'trade_tick_value_profit': 10.0, 'trade_tick_value_loss': 10.0, 'trade_tick_size': 0.01, 'trade_contract_size': 1.0, 'trade_accrued_interest': 0.0, 'trade_face_value': 0.0, 'trade_liquidity_rate': 0.0, 'volume_min': 1.0, 'volume_max': 1000.0, 'volume_step': 1.0, 'volume_limit': 0.0, 'swap_long': 0.0, 'swap_short': 0.0, 'margin_initial': 1000.0, 'margin_maintenance': 1000.0, 'session_volume': 0.0, 'session_turnover': 0.0, 'session_interest': 0.0, 'session_buy_orders_volume': 0.0, 'session_sell_orders_volume': 0.0, 'session_open': 0.0, 'session_close': 0.0, 'session_aw': 0.0, 'session_price_settlement': 0.0, 'session_price_limit_min': 0.0, 'session_price_limit_max': 0.0, 'margin_hedged': 0.0, 'price_change': 0.0, 'price_volatility': 0.0, 'price_theoretical': 0.0, 'price_greeks_delta': 0.0, 'price_greeks_theta': 0.0, 'price_greeks_gamma': 0.0, 'price_greeks_vega': 0.0, 'price_greeks_rho': 0.0, 'price_greeks_omega': 0.0, 'price_sensitivity': 0.0, 'basis': 'CLE', 'category': '', 'currency_base': 'USD', 'currency_profit': 'USD', 'currency_margin': 'USD', 'bank': '', 'description': 'Crude Light (Globex)', 'exchange': '', 'formula': '', 'isin': '', 'name': '@CLE', 'page': '', 'path': 'Exchange-Futures\\@CLE'}
filename = "test.csv"
if os.path.exists("test.csv"):
df = pd.read_csv(filename, index_col=0)
df = df.append(my_dict, ignore_index=True)
else:
df = pd.DataFrame(my_dict, index=[0])
df.to_csv("test.csv")
Судя по вашим предыдущим вопросам, вы читаете данные в цикле из WEB API по одной строке (строка данных приходит в виде словаря).
В таких условиях эффективнее всего накапливать словари (строки данных) в список и сохранять накопленные данные в БД пакетами по N записей. Другие ответы не учитывают особенности получения данных. Добавление записей в Pandas DataFrame по одной - очень медленная и неэффективная операция. Добавление DataFrame (df1.append(df2)) - работает еще медленнее и делать это в цикле крайне неэффективно.
Я бы решал вашу задачу так:
import sqlite3
import pandas as pd
db_filename = "/tmp/db.sqlite"
row_count = 0
batch_size = 10000
data = []
db_conn = sqlite3.connect(db_filename)
while time.time() < tempo:
symbol_info = mt5.symbol_info('@CLE')
if symbol_info:
data.append(symbol_info._asdict())
row_count += 1
if row_count == batch_size:
df = pd.DataFrame(data)
df.to_sql("data", db_conn, if_exists="append")
row_count = 0
data = []
чтение данных из БД
db_filename = "/tmp/db.sqlite"
db_conn = sqlite3.connect(db_filename)
d = pd.read_sql("select * from data", db_conn)
print(d.head())