diff --git a/Examples/Bars.py b/Examples/Bars.py index 1bfd216..7508680 100644 --- a/Examples/Bars.py +++ b/Examples/Bars.py @@ -128,48 +128,58 @@ def save_candles_to_file(tp_provider, class_code, security_codes, tf='D1', # tf, td = tp_provider.tinkoff_timeframe_to_timeframe(interval) # Временной интервал для имени файла и максимальный период запроса # _, intraday = tp_provider.timeframe_to_tinkoff_timeframe(tf) # Внутридневные бары for security_code in security_codes: # Пробегаемся по всем тикерам - si = tp_provider.get_symbol_info(class_code, security_code) # Информация о тикере - file_bars = load_candles_from_file(class_code, security_code, tf) # Получаем бары из файла - if file_bars.empty: # Если файла нет - next_bar_open_utc = datetime.fromtimestamp(si.first_1min_candle_date.seconds, timezone.utc) if intraday else \ - datetime.fromtimestamp(si.first_1day_candle_date.seconds, timezone.utc) # Первый минутный/дневной бар истории - else: # Если получили бары из файла - last_date: datetime = file_bars.index[-1] # Дата и время последнего бара по МСК - next_bar_open_utc = tp_provider.msk_to_utc_datetime(last_date + timedelta(minutes=1), True) if intraday else \ - last_date.replace(tzinfo=timezone.utc) + timedelta(days=1) # Смещаем время на возможный следующий бар по UTC - pd_bars = get_candles_from_provider(tp_provider, class_code, security_code, tf, next_bar_open_utc) # Получаем бары из провайдера - if pd_bars.empty: # Если бары не получены - logger.info('Новых бар нет') - continue # то переходим к следующему тикеру, дальше не продолжаем - if file_bars.empty and skip_first_date: # Если файла нет, и убираем бары на первую дату - len_with_first_date = len(pd_bars) # Кол-во бар до удаления на первую дату - first_date = pd_bars.index[0].date() # Первая дата - pd_bars.drop(pd_bars[(pd_bars.index.date == first_date)].index, inplace=True) # Удаляем их - logger.warning(f'Удалено бар на первую дату {first_date}: {len_with_first_date - len(pd_bars)}') - if skip_last_date: # Если убираем бары на последнюю дату - len_with_last_date = len(pd_bars) # Кол-во бар до удаления на последнюю дату - last_date = pd_bars.index[-1].date() # Последняя дата - pd_bars.drop(pd_bars[(pd_bars.index.date == last_date)].index, inplace=True) # Удаляем их - logger.warning(f'Удалено бар на последнюю дату {last_date}: {len_with_last_date - len(pd_bars)}') - if not four_price_doji: # Если удаляем дожи 4-х цен - len_with_doji = len(pd_bars) # Кол-во бар до удаления дожи - pd_bars.drop(pd_bars[(pd_bars.high == pd_bars.low)].index, inplace=True) # Удаляем их по условия High == Low - logger.warning(f'Удалено дожи 4-х цен: {len_with_doji - len(pd_bars)}') - if len(pd_bars) == 0: # Если нечего объединять - logger.info('Новых бар нет') - continue # то переходим к следующему тикеру, дальше не продолжаем - if not file_bars.empty: # Если файл существует - pd_bars = pd.concat([file_bars, pd_bars]) # Объединяем файл с данными из Tinkoff - pd_bars = pd_bars[~pd_bars.index.duplicated(keep='last')] # Убираем дубликаты самым быстрым методом - pd_bars.sort_index(inplace=True) # Сортируем по индексу заново - pd_bars = pd_bars[['open', 'high', 'low', 'close', 'volume']] # Отбираем нужные колонки. Дата и время будет экспортирована как индекс - filename = f'{datapath}{class_code}.{security_code}_{tf}.txt' - logger.info('Сохранение файла') - pd_bars.to_csv(filename, sep=delimiter, date_format=dt_format) - logger.info(f'Первый бар : {pd_bars.index[0]}') - logger.info(f'Последний бар : {pd_bars.index[-1]}') - logger.info(f'Кол-во бар : {len(pd_bars)}') - logger.info(f'В файл {filename} сохранено записей: {len(pd_bars)}') + try: # Оборачиваем обработку каждого тикера в try-except + si = tp_provider.get_symbol_info(class_code, security_code) # Информация о тикере + + if si is None: # Если информация о тикере не найдена + logger.warning(f'Информация о тикере {class_code}.{security_code} не найдена, пропускаем') + continue # Переходим к следующему тикеру + + file_bars = load_candles_from_file(class_code, security_code, tf) # Получаем бары из файла + if file_bars.empty: # Если файла нет + next_bar_open_utc = datetime.fromtimestamp(si.first_1min_candle_date.seconds, timezone.utc) if intraday else \ + datetime.fromtimestamp(si.first_1day_candle_date.seconds, timezone.utc) # Первый минутный/дневной бар истории + else: # Если получили бары из файла + last_date: datetime = file_bars.index[-1] # Дата и время последнего бара по МСК + next_bar_open_utc = tp_provider.msk_to_utc_datetime(last_date + timedelta(minutes=1), True) if intraday else \ + last_date.replace(tzinfo=timezone.utc) + timedelta(days=1) # Смещаем время на возможный следующий бар по UTC + pd_bars = get_candles_from_provider(tp_provider, class_code, security_code, tf, next_bar_open_utc) # Получаем бары из провайдера + if pd_bars.empty: # Если бары не получены + logger.info('Новых бар нет') + continue # то переходим к следующему тикеру, дальше не продолжаем + if file_bars.empty and skip_first_date: # Если файла нет, и убираем бары на первую дату + len_with_first_date = len(pd_bars) # Кол-во бар до удаления на первую дату + first_date = pd_bars.index[0].date() # Первая дата + pd_bars.drop(pd_bars[(pd_bars.index.date == first_date)].index, inplace=True) # Удаляем их + logger.warning(f'Удалено бар на первую дату {first_date}: {len_with_first_date - len(pd_bars)}') + if skip_last_date: # Если убираем бары на последнюю дату + len_with_last_date = len(pd_bars) # Кол-во бар до удаления на последнюю дату + last_date = pd_bars.index[-1].date() # Последняя дата + pd_bars.drop(pd_bars[(pd_bars.index.date == last_date)].index, inplace=True) # Удаляем их + logger.warning(f'Удалено бар на последнюю дату {last_date}: {len_with_last_date - len(pd_bars)}') + if not four_price_doji: # Если удаляем дожи 4-х цен + len_with_doji = len(pd_bars) # Кол-во бар до удаления дожи + pd_bars.drop(pd_bars[(pd_bars.high == pd_bars.low)].index, inplace=True) # Удаляем их по условия High == Low + logger.warning(f'Удалено дожи 4-х цен: {len_with_doji - len(pd_bars)}') + if len(pd_bars) == 0: # Если нечего объединять + logger.info('Новых бар нет') + continue # то переходим к следующему тикеру, дальше не продолжаем + if not file_bars.empty: # Если файл существует + pd_bars = pd.concat([file_bars, pd_bars]) # Объединяем файл с данными из Tinkoff + pd_bars = pd_bars[~pd_bars.index.duplicated(keep='last')] # Убираем дубликаты самым быстрым методом + pd_bars.sort_index(inplace=True) # Сортируем по индексу заново + pd_bars = pd_bars[['open', 'high', 'low', 'close', 'volume']] # Отбираем нужные колонки. Дата и время будет экспортирована как индекс + filename = f'{datapath}{class_code}.{security_code}_{tf}.txt' + logger.info('Сохранение файла') + pd_bars.to_csv(filename, sep=delimiter, date_format=dt_format) + logger.info(f'Первый бар : {pd_bars.index[0]}') + logger.info(f'Последний бар : {pd_bars.index[-1]}') + logger.info(f'Кол-во бар : {len(pd_bars)}') + logger.info(f'В файл {filename} сохранено записей: {len(pd_bars)}') + + except Exception as e: # Ловим любые ошибки при обработке тикера + logger.error(f'Ошибка при обработке тикера {class_code}.{security_code}: {e}') + continue # Переходим к следующему тикеру if __name__ == '__main__': # Точка входа при запуске этого скрипта @@ -184,6 +194,7 @@ def save_candles_to_file(tp_provider, class_code, security_codes, tf='D1', class_code = 'TQBR' # Акции ММВБ security_codes = ('SBER', 'GAZP') # Для тестов + # class_code = 'SPBFUT' # Фьючерсы # security_codes = ('SiM5', 'RIM5') # Формат фьючерса: <Тикер><Месяц экспирации><Последняя цифра года> Месяц экспирации: 3-H, 6-M, 9-U, 12-Z # security_codes = ('USDRUBF', 'EURRUBF', 'CNYRUBF', 'GLDRUBF', 'IMOEXF', 'SBERF', 'GAZPF') # Вечные фьючерсы ММВБ