
Методы Уильяма Ганна (Часть III): Работает ли астрология?
Введение
На финансовом рынке ведется извечный поиск все новых и новых методов анализа рынка и прогнозирования. Не обделяются вниманием даже самые невероятные концепции. Один из нестандартных и полностью уникальных подходов — это использование астрологии в трейдинге, которое было популяризовано известным трейдером Уильямом Ганном.
Мы уже затрагивали инструменты Ганна в прошлых статьях. Вот первая и вторая части. Сейчас мы сделаем фокус на исследовании влияния положения планет и звезд на рынки мира.
Попробуем объединить самые современные технологии и старинные знания, будем использовать язык программирования Python, а также платформу MetaTrader 5 для поиска связи астрономических явлений и движений пары евро-доллар. Охватим и теоретическую часть астрологии в финансах, попробуем себя и в практической части по разработке системы прогнозирования.
Рассмотрим процесс сбора и синхронизации астрономических и финансовых данных, составим корреляционную матрицу, и визуализируем результаты.
Теоретическая база астрологии в финансах
Знаете, я давно интересуюсь этой темой, и сегодня хочу поделиться своими мыслями о влиянии астрологии на финансовые рынки. Это действительно увлекательная область, хотя и весьма противоречивая.
Основная идея финансовой астрологии, как я понимаю, заключается в том, что движения небесных тел каким-то образом связаны с циклами на рынке. Эта концепция имеет длинную и богатую историю, и особую популярность приобрела благодаря Уильяму Ганну, знаменитому трейдеру прошлого века.
Я много размышлял над основными принципами этой теории. Например, идее о цикличности — что движения звезд и планет имеют циклическую природу, как и движения рынков. Или взять планетарные аспекты — некоторые считают, что определенные положения планет сильно влияют на рынки. А знаки зодиака? Говорят, что прохождение планет через разные зодиакальные созвездия тоже как-то воздействует на рынок.
Отдельно стоит упомянуть лунные циклы и солнечную активность. Я встречал мнения, что фазы Луны связаны с краткосрочными колебаниями на рынке, а солнечные вспышки — с долгосрочными трендами. Интересные гипотезы, не правда ли?
Уильям Ганн, кстати, был настоящим первопроходцем в этой области. Он разработал целый ряд инструментов, вроде его знаменитого квадрата 9, основанных на астрономии, геометрии и числовых последовательностях. Его работы до сих пор вызывают жаркие споры.
Конечно, нельзя не отметить, что научное сообщество в целом скептически относится к астрологии. Во многих странах она официально признана псевдонаукой. И честно говоря, строгих доказательств работоспособности астрологических методов в финансах пока нет. Часто те или иные наблюдаемые корреляции оказываются просто результатом когнитивных искажений.
Но знаете что? Несмотря на это, есть немало трейдеров, которые горячо отстаивают идеи финансовой астрологии. Это заставляет задуматься, не так ли?
Вот почему я решил провести собственное исследование. Хочу попробовать дать объективную оценку влияния астрологии на финансовые рынки, используя статистические методы и большие данные. Кто знает, может быть, мы обнаружим что-то интересное? В любом случае, это будет увлекательное путешествие в мир, где пересекаются звезды и биржевые графики.
Обзор используемых библиотек Python
Мне потребуется целый арсенал Python-библиотек.
Для начала, я решил использовать пакет Skyfield для получения астрономических данных. Знаете, я долго выбирал подходящий инструмент, и Skyfield меня впечатлил своей точностью. С его помощью я смогу собрать информацию о положениях небесных тел и фазах луны с очень высокой точностью по десятичным знакам — все то, что нужно для моих датасетов.
Что касается рыночных данных, тут мой выбор пал на официальную библиотеку MetaTrader 5 для Python. Она позволит загружать исторические данные по валютным парам и даже открывать сделки, если понадобится.
Pandas станет нашим верным спутником в работе с данными. Я часто использовал эту библиотеку раньше, и она просто незаменима для работы с временными рядами. Буду применять ее для предобработки и синхронизации всех собранных данных.
Для статистического анализа я остановился на библиотеке SciPy. Ее широкий функционал впечатляет, особенно инструменты для корреляционного и регрессионного анализа. Надеюсь, они помогут мне найти интересные закономерности.
А вот для визуализации результатов я решил использовать старых добрых друзей — Matplotlib и Seaborn. Люблю эти библиотеки за их гибкость в создании графиков. Уверен, они помогут нам наглядно представить все находки.
Весь набор собран. Это как собрать мощный компьютер из отличных комплектующих. Теперь у нас есть все необходимое, чтобы провести комплексное исследование влияния астрологических факторов на финансовые рынки. Не могу дождаться, когда погружусь в данные и начну тестировать свои гипотезы!
Сбор астрономических данных
import pandas as pd import numpy as np from skyfield.api import load, wgs84, utc from skyfield.data import mpc from datetime import datetime, timedelta import requests # Loading planet ephemerides planets = load('de421.bsp') earth = planets['earth'] ts = load.timescale() def get_planet_positions(date): t = ts.from_datetime(date.replace(tzinfo=utc)) planet_positions = {} planet_ids = { 'mercury': 'MERCURY BARYCENTER', 'venus': 'VENUS BARYCENTER', 'mars': 'MARS BARYCENTER', 'jupiter': 'JUPITER BARYCENTER', 'saturn': 'SATURN BARYCENTER', 'uranus': 'URANUS BARYCENTER', 'neptune': 'NEPTUNE BARYCENTER' } for planet, planet_id in planet_ids.items(): planet_obj = planets[planet_id] astrometric = earth.at(t).observe(planet_obj) ra, dec, _ = astrometric.radec() planet_positions[planet] = {'ra': ra.hours, 'dec': dec.degrees} return planet_positions def get_moon_phase(date): t = ts.from_datetime(date.replace(tzinfo=utc)) eph = load('de421.bsp') moon, sun, earth = eph['moon'], eph['sun'], eph['earth'] e = earth.at(t) _, m, _ = e.observe(moon).apparent().ecliptic_latlon() _, s, _ = e.observe(sun).apparent().ecliptic_latlon() phase = (m.degrees - s.degrees) % 360 return phase def get_solar_activity(date): # Get solar activity data from NOAA API url = f"https://services.swpc.noaa.gov/json/solar-cycle/observed-solar-cycle-indices.json" response = requests.get(url) data = response.json() # Convert date to 'YYYY-MM' format target_date = date.strftime("%Y-%m") # Find the closest date in the data closest_data = min(data, key=lambda x: abs(datetime.strptime(x['time-tag'], "%Y-%m") - datetime.strptime(target_date, "%Y-%m"))) return { 'sunspot_number': closest_data.get('ssn', None), 'f10.7_flux': closest_data.get('f10.7', None) } def calculate_aspects(positions): aspects = {} planets = list(positions.keys()) for i in range(len(planets)): for j in range(i+1, len(planets)): planet1 = planets[i] planet2 = planets[j] ra1 = positions[planet1]['ra'] ra2 = positions[planet2]['ra'] angle = abs(ra1 - ra2) % 24 angle = min(angle, 24 - angle) * 15 # Convert to degrees if abs(angle - 0) <= 10 or abs(angle - 180) <= 10: aspects[f"{planet1}_{planet2}"] = "conjunction" if abs(angle - 0) <= 10 else "opposition" elif abs(angle - 90) <= 10: aspects[f"{planet1}_{planet2}"] = "square" elif abs(angle - 120) <= 10: aspects[f"{planet1}_{planet2}"] = "trine" return aspects start_date = datetime(2024, 4, 1, tzinfo=utc) end_date = datetime(2024, 5, 31, tzinfo=utc) current_date = start_date astronomical_data = [] while current_date <= end_date: planet_positions = get_planet_positions(current_date) moon_phase = get_moon_phase(current_date) try: solar_activity = get_solar_activity(current_date) except Exception as e: print(f"Error getting solar activity for {current_date}: {e}") solar_activity = {'sunspot_number': None, 'f10.7_flux': None} aspects = calculate_aspects(planet_positions) data = { 'date': current_date, 'moon_phase': moon_phase, 'sunspot_number': solar_activity.get('sunspot_number'), 'f10.7_flux': solar_activity.get('f10.7_flux'), **planet_positions, **aspects } astronomical_data.append(data) current_date += timedelta(days=1) print(f"Processed: {current_date}") # Convert data to DataFrame df = pd.DataFrame(astronomical_data) # Save data to CSV file df.to_csv('astronomical_data_2018_2024.csv', index=False) print("Data saved to astronomical_data_2018_2024.csv")
Данный код на языке Python выполняет задачу сбора астрономических данных, которые мы будем использовать в будущем для анализа рынка.
Код берет периоды с 1 января 2018 года, по 31 мая 2024 года, и собирает ряд данных, таких как:
- Позиции планет – Венера, Меркурий, Марс, Юпитер, Сатурн, Уран, Нептун
- Фазы Луны
- Солнечная активность
- Аспекты планет (это когда планеты выстраиваются особым образом по отношению друг к другу)
Скрипт включает в себя импорты библиотек, основной цикл, и сохранение данных в формате Эксель. Код применяет уже озвученную библиотеку Skyfield для вычисления положений планет, Pandas для данных, и реквесты для получения данных по активности Солнца.
Из функций можно отметить get_planet_positions() для получения позиций планет (прямое восхождение и склонение), get_moon_phase() для определения текущей лунной фазы, get_solar_activity() для прямой поставки данных по солнечной активности из API NOAA, и calculate_aspects() для вычисления аспектов – положений планет по отношению друг к другу.
Мы в рамках цикла проходим по каждому из дней, и собираем все данные. В результате сохраняем все в один Эксель файл для будущего использования.
Получение финансовых данных через MetaTrader 5
Чтобы получать финансовые данные, мы будем использовать библиотеку MetaTrader 5 для Python. Библиотека позволит нам загружать финансовые данные сразу от брокера, и получать временные ряды цен по любому инструменту. Вот наш код для загрузки исторических данных:
import MetaTrader5 as mt5 import pandas as pd from datetime import datetime # Connect to MetaTrader5 if not mt5.initialize(): print("initialize() failed") mt5.shutdown() # Set query parameters symbol = "EURUSD" timeframe = mt5.TIMEFRAME_D1 start_date = datetime(2018, 1, 1) end_date = datetime(2024, 12, 31) # Request historical data rates = mt5.copy_rates_range(symbol, timeframe, start_date, end_date) # Convert data to DataFrame df = pd.DataFrame(rates) df['time'] = pd.to_datetime(df['time'], unit='s') # Save data to CSV file df.to_csv(f'{symbol}_data.csv', index=False) # Terminate the connection to MetaTrader5 mt5.shutdown()
Скрипт подключается к торговому терминалу, получает данные по паре евро-доллара с таймфреймом D1, затем создает датафрейм, и сохраняет его в один CSV файл.
Синхронизация астрономических и финансовых данных
Итак, у нас есть данные по астрономии, у нас также есть данные по евро-доллару. Встает задача их синхронизации. Объединим данные по датам, чтобы единый датасет у нас содержал всю нужную информацию, как финансовую, так и астрономическую.
import pandas as pd # Load data astro_data = pd.read_csv('astronomical_data_2018_2024.csv') financial_data = pd.read_csv('EURUSD_data.csv') # Convert date columns to datetime astro_data['date'] = pd.to_datetime(astro_data['date']) financial_data['time'] = pd.to_datetime(financial_data['time']) # Merge data merged_data = pd.merge(financial_data, astro_data, left_on='time', right_on='date', how='inner') # Save merged data merged_data.to_csv('merged_astro_financial_data.csv', index=False)
Скрипт грузит все сохраненные данные, форматирует столбцы дат в формат datetime, и соединяет датасеты по дате. В итоге получаем CSV файл, который содержит в себе все нужные нам для будущего анализа данные.
Статистический анализ корреляций
Итак, едем дальше. У нас есть общий набор, общий датасет, и пришло время выяснить, есть ли в данных хоть какие-то зависимости между данными астрономии и движениями на рынках. Будем использовать функции corr() из библиотеки pandas. Ну и объединим оба наших кода в один.
Вот итоговый скрипт:
import pandas as pd import numpy as np from skyfield.api import load, wgs84, utc from skyfield.data import mpc from datetime import datetime, timedelta import requests import MetaTrader5 as mt5 import seaborn as sns import matplotlib.pyplot as plt # Part 1: Collecting astronomical data # Loading planetary ephemerides planets = load('de421.bsp') earth = planets['earth'] ts = load.timescale() def get_planet_positions(date): t = ts.from_datetime(date.replace(tzinfo=utc)) planet_positions = {} planet_ids = { 'mercury': 'MERCURY BARYCENTER', 'venus': 'VENUS BARYCENTER', 'mars': 'MARS BARYCENTER', 'jupiter': 'JUPITER BARYCENTER', 'saturn': 'SATURN BARYCENTER', 'uranus': 'URANUS BARYCENTER', 'neptune': 'NEPTUNE BARYCENTER' } for planet, planet_id in planet_ids.items(): planet_obj = planets[planet_id] astrometric = earth.at(t).observe(planet_obj) ra, dec, _ = astrometric.radec() planet_positions[planet] = {'ra': ra.hours, 'dec': dec.degrees} return planet_positions def get_moon_phase(date): t = ts.from_datetime(date.replace(tzinfo=utc)) eph = load('de421.bsp') moon, sun, earth = eph['moon'], eph['sun'], eph['earth'] e = earth.at(t) _, m, _ = e.observe(moon).apparent().ecliptic_latlon() _, s, _ = e.observe(sun).apparent().ecliptic_latlon() phase = (m.degrees - s.degrees) % 360 return phase def get_solar_activity(date): url = f"https://services.swpc.noaa.gov/json/solar-cycle/observed-solar-cycle-indices.json" response = requests.get(url) data = response.json() target_date = date.strftime("%Y-%m") closest_data = min(data, key=lambda x: abs(datetime.strptime(x['time-tag'], "%Y-%m") - datetime.strptime(target_date, "%Y-%m"))) return { 'sunspot_number': closest_data.get('ssn', None), 'f10.7_flux': closest_data.get('f10.7', None) } def calculate_aspects(positions): aspects = {} planets = list(positions.keys()) for i in range(len(planets)): for j in range(i+1, len(planets)): planet1 = planets[i] planet2 = planets[j] ra1 = positions[planet1]['ra'] ra2 = positions[planet2]['ra'] angle = abs(ra1 - ra2) % 24 angle = min(angle, 24 - angle) * 15 # Convert to degrees if abs(angle - 0) <= 10 or abs(angle - 180) <= 10: aspects[f"{planet1}_{planet2}"] = "conjunction" if abs(angle - 0) <= 10 else "opposition" elif abs(angle - 90) <= 10: aspects[f"{planet1}_{planet2}"] = "square" elif abs(angle - 120) <= 10: aspects[f"{planet1}_{planet2}"] = "trine" return aspects # Collecting astronomical data start_date = datetime(2024, 3, 1, tzinfo=utc) end_date = datetime(2024, 7, 30, tzinfo=utc) current_date = start_date astronomical_data = [] while current_date <= end_date: planet_positions = get_planet_positions(current_date) moon_phase = get_moon_phase(current_date) try: solar_activity = get_solar_activity(current_date) except Exception as e: print(f"Error getting solar activity for {current_date}: {e}") solar_activity = {'sunspot_number': None, 'f10.7_flux': None} aspects = calculate_aspects(planet_positions) data = { 'date': current_date, 'moon_phase': moon_phase, 'sunspot_number': solar_activity.get('sunspot_number'), 'f10.7_flux': solar_activity.get('f10.7_flux'), **planet_positions, **aspects } astronomical_data.append(data) current_date += timedelta(days=1) print(f"Processed: {current_date}") # Convert data to DataFrame and save astro_df = pd.DataFrame(astronomical_data) astro_df.to_csv('astronomical_data_2018_2024.csv', index=False) print("Astronomical data saved to astronomical_data_2018_2024.csv") # Part 2: Retrieving financial data via MetaTrader5 # Initialize connection to MetaTrader5 if not mt5.initialize(): print("initialize() failed") mt5.shutdown() # Set request parameters symbol = "EURUSD" timeframe = mt5.TIMEFRAME_D1 start_date = datetime(2024, 3, 1) end_date = datetime(2024, 7, 30) # Request historical data rates = mt5.copy_rates_range(symbol, timeframe, start_date, end_date) # Convert data to DataFrame financial_df = pd.DataFrame(rates) financial_df['time'] = pd.to_datetime(financial_df['time'], unit='s') # Save financial data financial_df.to_csv(f'{symbol}_data.csv', index=False) print(f"Financial data saved to {symbol}_data.csv") # Shutdown MetaTrader5 connection mt5.shutdown() # Part 3: Synchronizing astronomical and financial data # Load data astro_df = pd.read_csv('astronomical_data_2018_2024.csv') financial_df = pd.read_csv('EURUSD_data.csv') # Convert date columns to datetime astro_df['date'] = pd.to_datetime(astro_df['date']).dt.tz_localize(None) financial_df['time'] = pd.to_datetime(financial_df['time']) # Merge data merged_data = pd.merge(financial_df, astro_df, left_on='time', right_on='date', how='inner') # Save merged data merged_data.to_csv('merged_astro_financial_data.csv', index=False) print("Merged data saved to merged_astro_financial_data.csv") # Part 4: Statistical analysis of correlations # Select numeric columns for correlation analysis numeric_columns = merged_data.select_dtypes(include=[np.number]).columns # Create lags for astronomical data for col in numeric_columns: if col not in ['open', 'high', 'low', 'close', 'tick_volume', 'spread', 'real_volume']: for lag in range(1, 6): # Create lags from 1 to 5 merged_data[f'{col}_lag{lag}'] = merged_data[col].shift(lag) # Update list of numeric columns numeric_columns = merged_data.select_dtypes(include=[np.number]).columns # Calculate correlation matrix correlation_matrix = merged_data[numeric_columns].corr() # Create heatmap of correlations plt.figure(figsize=(20, 16)) sns.heatmap(correlation_matrix, annot=False, cmap='coolwarm', vmin=-1, vmax=1, center=0) plt.title('Correlation Matrix of Astronomical Factors (with Lags) and EURUSD Prices') plt.tight_layout() plt.savefig('correlation_heatmap_with_lags.png') plt.close() # Output the most significant correlations with the closing price significant_correlations = correlation_matrix['close'].sort_values(key=abs, ascending=False) print("Most significant correlations with the closing price:") print(significant_correlations) # Create a separate correlation matrix for astronomical data with lags and the current price astro_columns = [col for col in numeric_columns if col not in ['open', 'high', 'low', 'tick_volume', 'spread', 'real_volume']] astro_columns.append('close') # Add the current closing price astro_correlation_matrix = merged_data[astro_columns].corr() # Create heatmap of correlations for astronomical data with lags and the current price import seaborn as sns import matplotlib.pyplot as plt # Увеличиваем шрифт заголовка и меток осей plt.figure(figsize=(18, 14)) sns.heatmap(astro_correlation_matrix, annot=False, cmap='coolwarm', vmin=-1, vmax=1, center=0, cbar_kws={'label': 'Correlation'}) plt.title('Correlation matrix of astronomical factors (with lags) and current EURUSD price', fontsize=24) plt.xlabel('X-axis Label', fontsize=30) plt.ylabel('Y-axis Label', fontsize=30) plt.xticks(fontsize=30) plt.yticks(fontsize=30) plt.tight_layout() plt.savefig('astro_correlation_heatmap_with_lags.png') plt.close() print("Analysis completed. Results saved in CSV and PNG files.")
Данный скрипт выводит карту корреляций между всеми числами в наборе данных, а также выводит матрицу всех корреляций в формате heatmap, и выдает список самых значимых корреляций с ценами close.
Наличие или отсутствие корреляции не означает наличия или отсутствия причинно-следственной связи. Даже если мы и нашли бы мощные корреляции между астрономическими данными и движениям цен, это не сказало бы, что один фактор определяет другой , и наоборот. Нужны новые исследования, ведь карта корреляций — лишь самое элементарное.
Если прийти ближе к теме, то какой-либо значимой корреляции в данных нам обнаружить не удается. Среди прошлых показателей астрономии нет явно коррелирующих с показателями рынка.
Призываем на помощь машинное обучение
Затем я задумался, что же делать дальше, и было решено призвать на помощь модель машинного обучения. Я сделал два скрипта на библиотеке CatBoost, которые пытаются прогнозировать будущие цены, используя в качестве признаков данные датасета. Вот первая из моделей — регрессионная:
import pandas as pd import numpy as np from catboost import CatBoostRegressor from sklearn.model_selection import train_test_split from sklearn.metrics import mean_squared_error, mean_absolute_error, r2_score import matplotlib.pyplot as plt from sklearn.preprocessing import LabelEncoder # Loading data data = pd.read_csv('merged_astro_financial_data.csv') # Converting date to datetime data['date'] = pd.to_datetime(data['date']) # Creating lags for financial data for col in ['open', 'high', 'low', 'close']: for lag in range(1, 6): # Creating lags from 1 to 5 data[f'{col}_lag{lag}'] = data[col].shift(lag) # Creating lags for astronomical data astro_cols = ['mercury', 'venus', 'mars', 'jupiter', 'saturn', 'uranus', 'neptune'] for col in astro_cols: data[f'{col}_ra'] = data[col].apply(lambda x: eval(x)['ra'] if pd.notna(x) else np.nan) data[f'{col}_dec'] = data[col].apply(lambda x: eval(x)['dec'] if pd.notna(x) else np.nan) for lag in range(1, 6): # Lags from 1 to 5 data[f'{col}_ra_lag{lag}'] = data[f'{col}_ra'].shift(lag) data[f'{col}_dec_lag{lag}'] = data[f'{col}_dec'].shift(lag) data.drop(columns=[col, f'{col}_ra', f'{col}_dec'], inplace=True) # Converting aspects to numerical features aspect_cols = ['mercury_saturn', 'venus_mars', 'venus_jupiter', 'venus_uranus', 'mars_jupiter', 'mars_uranus', 'jupiter_uranus', 'mercury_neptune', 'venus_saturn', 'venus_neptune', 'mars_saturn', 'mercury_venus', 'mars_neptune', 'mercury_uranus', 'saturn_neptune', 'mercury_jupiter', 'mercury_mars', 'jupiter_saturn'] # Using LabelEncoder for encoding aspects label_encoders = {} for col in aspect_cols: label_encoders[col] = LabelEncoder() data[col] = label_encoders[col].fit_transform(data[col].astype(str)) # Filling missing values with mean values for numeric columns numeric_cols = data.select_dtypes(include=[np.number]).columns data[numeric_cols] = data[numeric_cols].fillna(data[numeric_cols].mean()) # Removing rows with missing values data = data.dropna() # Preparing features and target variable features = [col for col in data.columns if col not in ['date', 'time', 'close']] X = data[features] y = data['close'] # Splitting data into training and testing sets X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=1) # Creating and training the CatBoost model model = CatBoostRegressor(iterations=500, learning_rate=0.1, depth=9, random_state=1) model.fit(X_train, y_train, eval_set=(X_test, y_test), early_stopping_rounds=200, verbose=100) # Evaluating the model y_pred = model.predict(X_test) mse = mean_squared_error(y_test, y_pred) mae = mean_absolute_error(y_test, y_pred) r2 = r2_score(y_test, y_pred) print(f"Mean Squared Error: {mse}") print(f"Mean Absolute Error: {mae}") print(f"R-squared Score: {r2}") # Visualizing feature importance feature_importance = model.feature_importances_ feature_names = X.columns sorted_idx = np.argsort(feature_importance) pos = np.arange(sorted_idx.shape[0]) + 0.5 plt.figure(figsize=(12, 6)) plt.barh(pos, feature_importance[sorted_idx], align='center') plt.yticks(pos, np.array(feature_names)[sorted_idx]) plt.xlabel('Feature Importance') plt.title('Feature Importance') plt.show() # Predicting the next value def predict_next(): # Selecting the last row of data last_data = data.iloc[-1] input_features = last_data[features].values.reshape(1, -1) # Prediction prediction = model.predict(input_features) print(f"Prediction for the next closing price: {prediction[0]}") # Example of using the function to predict the next value predict_next()
Вторая модель — классификация:
import pandas as pd import numpy as np from skyfield.api import load, utc from datetime import datetime, timedelta import requests import MetaTrader5 as mt5 import seaborn as sns import matplotlib.pyplot as plt from catboost import CatBoostClassifier from sklearn.model_selection import train_test_split from sklearn.metrics import accuracy_score, classification_report, confusion_matrix from sklearn.preprocessing import LabelEncoder # Part 1: Collecting astronomical data planets = load('de421.bsp') earth = planets['earth'] ts = load.timescale() def get_planet_positions(date): t = ts.from_datetime(date.replace(tzinfo=utc)) planet_positions = {} planet_ids = { 'mercury': 'MERCURY BARYCENTER', 'venus': 'VENUS BARYCENTER', 'mars': 'MARS BARYCENTER', 'jupiter': 'JUPITER BARYCENTER', 'saturn': 'SATURN BARYCENTER', 'uranus': 'URANUS BARYCENTER', 'neptune': 'NEPTUNE BARYCENTER' } for planet, planet_id in planet_ids.items(): planet_obj = planets[planet_id] astrometric = earth.at(t).observe(planet_obj) ra, dec, _ = astrometric.radec() planet_positions[planet] = {'ra': ra.hours, 'dec': dec.degrees} return planet_positions def get_moon_phase(date): t = ts.from_datetime(date.replace(tzinfo=utc)) eph = load('de421.bsp') moon, sun, earth = eph['moon'], eph['sun'], eph['earth'] e = earth.at(t) _, m, _ = e.observe(moon).apparent().ecliptic_latlon() _, s, _ = e.observe(sun).apparent().ecliptic_latlon() phase = (m.degrees - s.degrees) % 360 return phase def get_solar_activity(date): url = f"https://services.swpc.noaa.gov/json/solar-cycle/observed-solar-cycle-indices.json" response = requests.get(url) data = response.json() target_date = date.strftime("%Y-%m") closest_data = min(data, key=lambda x: abs(datetime.strptime(x['time-tag'], "%Y-%m") - datetime.strptime(target_date, "%Y-%m"))) return { 'sunspot_number': closest_data.get('ssn', None), 'f10.7_flux': closest_data.get('f10.7', None) } def calculate_aspects(positions): aspects = {} planets = list(positions.keys()) for i in range(len(planets)): for j in range(i+1, len(planets)): planet1 = planets[i] planet2 = planets[j] ra1 = positions[planet1]['ra'] ra2 = positions[planet2]['ra'] angle = abs(ra1 - ra2) % 24 angle = min(angle, 24 - angle) * 15 # Convert to degrees if abs(angle - 0) <= 10 or abs(angle - 180) <= 10: aspects[f"{planet1}_{planet2}"] = "conjunction" if abs(angle - 0) <= 10 else "opposition" elif abs(angle - 90) <= 10: aspects[f"{planet1}_{planet2}"] = "square" elif abs(angle - 120) <= 10: aspects[f"{planet1}_{planet2}"] = "trine" return aspects # Part 2: Obtaining financial data through MetaTrader5 def get_financial_data(symbol, start_date, end_date): if not mt5.initialize(): print("initialize() failed") mt5.shutdown() return None timeframe = mt5.TIMEFRAME_D1 rates = mt5.copy_rates_range(symbol, timeframe, start_date, end_date) mt5.shutdown() financial_df = pd.DataFrame(rates) financial_df['time'] = pd.to_datetime(financial_df['time'], unit='s') return financial_df # Part 3: Synchronizing astronomical and financial data def sync_data(astro_df, financial_df): astro_df['date'] = pd.to_datetime(astro_df['date']).dt.tz_localize(None) financial_df['time'] = pd.to_datetime(financial_df['time']) merged_data = pd.merge(financial_df, astro_df, left_on='time', right_on='date', how='inner') return merged_data # Part 4: Training the model and making predictions def train_and_predict(merged_data): # Converting aspects to numerical features aspect_cols = [col for col in merged_data.columns if '_' in col and col not in ['date', 'time']] label_encoders = {} for col in aspect_cols: label_encoders[col] = LabelEncoder() merged_data[col] = label_encoders[col].fit_transform(merged_data[col].astype(str)) # Creating lags for financial data for col in ['open', 'high', 'low', 'close']: for lag in range(1, 6): merged_data[f'{col}_lag{lag}'] = merged_data[col].shift(lag) # Creating lags for astronomical data astro_cols = ['mercury', 'venus', 'mars', 'jupiter', 'saturn', 'uranus', 'neptune'] for col in astro_cols: merged_data[f'{col}_ra'] = merged_data[col].apply(lambda x: eval(x)['ra'] if pd.notna(x) else np.nan) merged_data[f'{col}_dec'] = merged_data[col].apply(lambda x: eval(x)['dec'] if pd.notna(x) else np.nan) for lag in range(1, 6): merged_data[f'{col}_ra_lag{lag}'] = merged_data[f'{col}_ra'].shift(lag) merged_data[f'{col}_dec_lag{lag}'] = merged_data[f'{col}_dec'].shift(lag) merged_data.drop(columns=[col, f'{col}_ra', f'{col}_dec'], inplace=True) # Filling missing values with mean values for numeric columns numeric_cols = merged_data.select_dtypes(include=[np.number]).columns merged_data[numeric_cols] = merged_data[numeric_cols].fillna(merged_data[numeric_cols].mean()) merged_data = merged_data.dropna() # Creating binary target variable merged_data['price_change'] = (merged_data['close'].shift(-1) > merged_data['close']).astype(int) # Removing rows with missing values in the target variable merged_data = merged_data.dropna(subset=['price_change']) features = [col for col in merged_data.columns if col not in ['date', 'time', 'close', 'price_change']] X = merged_data[features] y = merged_data['price_change'] X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=1) model = CatBoostClassifier(iterations=500, learning_rate=0.1, depth=9, random_state=1) model.fit(X_train, y_train, eval_set=(X_test, y_test), early_stopping_rounds=200, verbose=100) y_pred = model.predict(X_test) accuracy = accuracy_score(y_test, y_pred) clf_report = classification_report(y_test, y_pred) conf_matrix = confusion_matrix(y_test, y_pred) print(f"Accuracy: {accuracy}") print("Classification Report:") print(clf_report) print("Confusion Matrix:") print(conf_matrix) # Visualizing feature importance feature_importance = model.feature_importances_ feature_names = X.columns sorted_idx = np.argsort(feature_importance) pos = np.arange(sorted_idx.shape[0]) + 0.5 plt.figure(figsize=(12, 6)) plt.barh(pos, feature_importance[sorted_idx], align='center') plt.yticks(pos, np.array(feature_names)[sorted_idx]) plt.xlabel('Feature Importance') plt.title('Feature Importance') plt.show() # Predicting the next value def predict_next(): last_data = merged_data.iloc[-1] input_features = last_data[features].values.reshape(1, -1) prediction = model.predict(input_features) print(f"Price change prediction (0: will decrease, 1: will increase): {prediction[0]}") predict_next() # Main program start_date = datetime(2023, 3, 1) end_date = datetime(2024, 7, 30) astro_data = [] current_date = start_date while current_date <= end_date: planet_positions = get_planet_positions(current_date) moon_phase = get_moon_phase(current_date) try: solar_activity = get_solar_activity(current_date) except Exception as e: print(f"Error getting solar activity for {current_date}: {e}") solar_activity = {'sunspot_number': None, 'f10.7_flux': None} aspects = calculate_aspects(planet_positions) astro_data.append({ 'date': current_date, 'mercury': str(planet_positions['mercury']), 'venus': str(planet_positions['venus']), 'mars': str(planet_positions['mars']), 'jupiter': str(planet_positions['jupiter']), 'saturn': str(planet_positions['saturn']), 'uranus': str(planet_positions['uranus']), 'neptune': str(planet_positions['neptune']), 'moon_phase': moon_phase, **solar_activity, **aspects }) current_date += timedelta(days=1) astro_df = pd.DataFrame(astro_data) symbol = "EURUSD" financial_data = get_financial_data(symbol, start_date, end_date) if financial_data is not None: merged_data = sync_data(astro_df, financial_data) train_and_predict(merged_data)
К сожалению, ни одна, ни вторая модель не дает большой точности. Точность классификации у меня получается чуть выше 50%, то есть, мы можем с тем же успехом прогнозировать по подброшенной монетке.
Возможно, результат можно улучшить, возможно, что регрессионной модели было уделено мало внимания, и на самом деле прогнозировать цены с помощью положения планет и активности Луны и Солнца все же возможно. Если будет настроение — я сделаю еще одну статью на эту тему.
Результаты исследования
Итак, пришло время подвести результаты исследования. После проведения простого анализа, и написания двух моделей прогнозирования, мы видим результаты исследования о потенциальном влиянии астрологии на рынок.
Корреляционный анализ. Полученная нами карта взаимозависимостей не выявила какой-либо плотной корреляции между положением планет и ценой закрытия EURUSD. Все корреляции у нас – слабее 0.3, что дает основания полагать, что положение звезд или планет вообще никак не связано с финансовыми рынками.
Модель регрессии CatBoost. Итоговые показатели модели регрессии показали весьма слабые возможности в прогнозах точных значений будущих цен закрытия на основе данных астрономии.
Полученные метрики результатов модели, такие как MSE, MAE, и R квадрат – очень слабы, и объясняют данные очень слабо. При этом, модель показывает, что самыми важными признаками являются лаги, предыдущие значения цен, а вовсе не положения планет. Значит, что цена является лучшим признаком, нежели положение любой планеты нашей солнечной системы?
Модель классификации CatBoost. Модель классификации крайне плохо прогнозирует будущий рост или падение цен. Точность едва превышает 50%, что также подтверждает — астрономия никак не работает на реальном рынке.
Заключение
Итоги исследования вполне явны — методы астрологии, и попытки прогноза цен на реальном рынке по данным астрономических признаков — полностью бесполезны. Возможно, я еще вернусь к этой теме, но пока что учение Уильяма Ганна выглядит как «наведение тени на плетень», и попытки замаскировать за сложностью по факту нерабочие решения, которые были созданы лишь с целью продажи книг и курсов по трейдингу.
Может ли быть, что улучшенная модель, где также использовались бы значения углов Ганна, значения из выстроенного квадрата 9, а также значения сетки Ганна, показала бы себя лучше? Пока что мы этого не знаем. Я немного разочарован результатами исследования.
Все же есть мысли о том, что углы Ганна так или иначе могут быть использованы для получения рабочих прогнозов цен. Цена так или иначе затрагивает углы, она реагирует на них, что видно из результатов прошлого исследования. Возможно и такое, что углы могут быть применены в качестве рабочих признаков для обучения моделей. Я в любом случае попробую создать подобный датасет, и посмотреть, что же выйдет в результате.





- Бесплатные приложения для трейдинга
- 8 000+ сигналов для копирования
- Экономические новости для анализа финансовых рынков
Вы принимаете политику сайта и условия использования
по стопам Гана, для чистоты опыта стоило брать не EURUSD а например фьюч на хлопок. И инструмент примерно тот-же и астрономические циклы в нём могут быть, всё-же сельхоз.