English Русский 中文 Deutsch 日本語 Português
preview
Métodos de William Gann (Parte III): ¿Funciona la astrología?

Métodos de William Gann (Parte III): ¿Funciona la astrología?

MetaTrader 5Probador |
200 2
Yevgeniy Koshtenko
Yevgeniy Koshtenko

Introducción

Los participantes del mercado financiero buscan constantemente métodos cada vez más nuevos de análisis y previsión del mercado. Ni siquiera los conceptos más increíbles quedan fuera. Uno de los enfoques no estándar y completamente únicos es el uso de la astrología en el trading, que fue popularizado por el famoso trader William Gann.

Ya hemos hablado de las herramientas de Gann en nuestros artículos anteriores. Aquí están las partes primera y segunda. Ahora nos centraremos en explorar el impacto de las posiciones planetarias y estelares en los mercados mundiales.

Intentemos combinar las tecnologías más modernas y los conocimientos antiguos. Utilizaremos el lenguaje de programación Python, así como la plataforma MetaTrader 5 para encontrar la conexión entre los fenómenos astronómicos y los movimientos del par EURUSD. Cubriremos la parte teórica de la astrología en las finanzas y nos probaremos en la parte práctica del desarrollo de un sistema de pronóstico.

Además, analizaremos cómo recopilar y sincronizar datos astronómicos y financieros, crearemos una matriz de correlación y visualizaremos los resultados. 


Bases teóricas de la astrología en las finanzas

Este tema me ha interesado durante mucho tiempo y hoy quiero compartir mis pensamientos sobre la influencia de la astrología en los mercados financieros. Se trata de un área realmente fascinante, aunque bastante controvertida.

La idea básica de la astrología financiera, tal como la entiendo, es que los movimientos de los cuerpos celestes están de alguna manera relacionados con los ciclos del mercado. Este concepto tiene una larga y rica historia, y fue especialmente popularizado por William Gann, un famoso comerciante del siglo pasado.

He pensado mucho sobre los principios básicos de esta teoría. Por ejemplo, la idea del ciclismo que afirma que los movimientos de las estrellas y los planetas son de naturaleza cíclica, al igual que los movimientos del mercado. En términos de aspectos planetarios, algunos creen que ciertas posiciones planetarias tienen una fuerte influencia en los mercados. ¿Y qué pasa con los signos del zodiaco? Se cree que el paso de los planetas por las diferentes constelaciones del zodíaco también afecta de alguna manera al mercado.

También vale la pena mencionar los ciclos lunares y la actividad solar. He visto opiniones de que las fases de la luna están asociadas con fluctuaciones a corto plazo en el mercado, mientras que las erupciones solares están asociadas con tendencias a largo plazo. Son hipótesis interesantes ¿no?

William Gunn fue un verdadero pionero en este campo. Desarrolló una serie de herramientas, como su famoso cuadrado de 9, basado en la astronomía, la geometría y las secuencias numéricas. Sus obras aún hoy suscitan acalorados debates.

Por supuesto, no se puede ignorar que la comunidad científica en su conjunto es escéptica respecto de la astrología. En muchos países se reconoce oficialmente como pseudociencia. Y, francamente, todavía no hay evidencia estricta de la eficiencia de los métodos astrológicos en las finanzas. A menudo, ciertas correlaciones observadas resultan ser simplemente el resultado de sesgos cognitivos.

A pesar de ello, hay muchos traders que defienden ardientemente las ideas de la astrología financiera.

Por eso decidí hacer mi propia investigación. Me gustaría intentar dar una evaluación objetiva de la influencia de la astrología en los mercados financieros utilizando métodos estadísticos y big data. Quien sabe, quizás descubramos algo interesante. De cualquier manera, será un viaje fascinante al mundo donde las estrellas y los gráficos bursátiles se cruzan.


Descripción general de las bibliotecas de Python aplicadas

Necesitaré todo un arsenal de bibliotecas de Python. 

Para empezar, decidí utilizar el paquete Skyfield para obtener datos astronómicos. Pasé mucho tiempo eligiendo la herramienta adecuada y Skyfield me impresionó con su precisión. Con su ayuda, podré recopilar información sobre las posiciones de los cuerpos celestes y las fases de la luna con una precisión muy alta en decimales: todo lo que necesito para mis conjuntos de datos.

En cuanto a los datos de mercado, mi elección recayó en la biblioteca oficial de MetaTrader 5 para Python. Permitirá descargar datos históricos sobre pares de divisas e incluso abrir operaciones si es necesario.

Los pandas se convertirán en nuestro fiel compañero en el trabajo con datos. He utilizado mucho esta biblioteca en el pasado y es simplemente indispensable para trabajar con series de tiempo. Lo utilizaré para el preprocesamiento y la sincronización de todos los datos recopilados.

Para el análisis estadístico, opté por la biblioteca SciPy. Su amplia funcionalidad es impresionante, especialmente las herramientas para el análisis de correlación y regresión. Espero que me ayuden a encontrar patrones interesantes.

Para visualizar los resultados, decidí utilizar a mis viejos amigos: Matplotlib y Seaborn. Me encantan estas bibliotecas por su flexibilidad en la creación de gráficos. Estoy seguro de que ayudarán a visualizar todos los hallazgos.

Todo el conjunto está montado. Es como montar un PC potente con componentes excelentes. Ahora tenemos todo lo que necesitamos para realizar un estudio exhaustivo de la influencia de los factores astrológicos en los mercados financieros. ¡No puedo esperar para sumergirme en los datos y comenzar a probar mis hipótesis!


Recopilación de datos astronómicos

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")

Este código Python recopila datos astronómicos que usaremos en el futuro para el análisis de mercado.

El código utiliza el período del 1 de enero de 2018 al 31 de mayo de 2024 y recopila una variedad de datos como:

  • Posiciones de los planetas: Venus, Mercurio, Marte, Júpiter, Saturno, Urano y Neptuno
  • Fases lunares
  • Actividad solar
  • Aspectos planetarios (cómo se alinean los planetas entre sí)

El script incluye importaciones de biblioteca, el bucle principal y el guardado de datos en formato Excel. El código utiliza la biblioteca Skyfield ya mencionada para calcular las posiciones de los planetas, Pandas para los datos y solicitudes para obtener datos de actividad solar.

Las funciones más destacadas son get_planet_positions() para obtener las posiciones de los planetas (ascensión recta y declinación), get_moon_phase() para conocer la fase lunar actual, get_solar_activity() para obtener directamente los datos de actividad solar de la API de la NOAA, y calculate_aspects() para calcular los aspectos, es decir, las posiciones de los planetas entre sí.

Recorremos cada día como parte del ciclo y recopilamos todos los datos. Como resultado, guardamos todo en un archivo Excel para uso futuro. 


Obtención de datos financieros a través de MetaTrader 5

Para obtener datos financieros, utilizaremos la biblioteca MetaTrader 5 para Python. La biblioteca nos permitirá descargar datos financieros directamente del broker y recibir series temporales de precios para cualquier instrumento. Aquí está nuestro código para cargar datos históricos: 

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()

El script se conecta a la terminal comercial, recibe datos sobre EURUSD D1, luego crea un marco de datos y lo guarda en un solo archivo CSV. 


Sincronización de datos astronómicos y financieros

Entonces, tenemos datos sobre astronomía y también tenemos datos sobre el EURUSD. Ahora tenemos que sincronizarlos. Combinemos los datos por fechas para que un único conjunto de datos contenga toda la información necesaria, tanto financiera como astronómica.

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)

El script carga todos los datos guardados, formatea las columnas de fecha en formato de fecha y hora y combina conjuntos de datos por fecha. Como resultado, obtenemos un archivo CSV que contiene todos los datos que necesitamos para el análisis futuro.


Análisis estadístico de correlaciones

Sigamos adelante. Tenemos un conjunto común, un conjunto de datos común, y es hora de descubrir si existen relaciones en los datos entre la astronomía y los movimientos del mercado. Utilizaremos las funciones corr() de la biblioteca pandas. Además, combinaremos ambos códigos en uno.

Aquí está el script final:

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

# Increase the header and axis label font
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.")

Este script muestra un mapa de las correlaciones entre todos los números del conjunto de datos, y también una matriz de todas las correlaciones en formato de mapa de calor, además de producir una lista de las correlaciones más significativas con los precios de cierre.

La presencia o ausencia de una correlación no implica la presencia o ausencia de una relación causal. Incluso si encontráramos fuertes correlaciones entre datos astronómicos y movimientos de precios, esto no significaría que un factor determine al otro, y viceversa. Se necesitan nuevas investigaciones, ya que el mapa de correlación es sólo lo más básico.


Si nos acercamos al tema, no podemos encontrar ninguna correlación significativa en los datos. No existen correlaciones claras entre los datos astronómicos pasados y los indicadores del mercado.


El aprendizaje automático al rescate

Pensé en qué hacer a continuación y decidí aplicar un modelo de aprendizaje automático. Hice dos scripts usando la biblioteca CatBoost que intentan predecir precios futuros usando datos del conjunto de datos como características. Aquí está el primero de los modelos, uno de regresión: 

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()


El segundo modelo es la clasificación:

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)

Desafortunadamente ninguno de los dos modelos proporciona gran precisión. La precisión de la clasificación es ligeramente superior al 50%, lo que significa que podemos hacer predicciones con la misma facilidad con solo lanzar una moneda.


Tal vez el resultado se pueda mejorar, ya que se le ha prestado poca atención al modelo de regresión y, de hecho, es posible predecir los precios utilizando las posiciones planetarias y la actividad de la Luna y el Sol. Haré otro artículo sobre este tema si estoy de humor.


Resultados

Así pues, es hora de resumir los resultados. Después de realizar un análisis simple y escribir dos modelos de predicción, vemos los resultados del estudio sobre el impacto potencial de la astrología en el mercado. 

Análisis de correlación. El mapa de correlación que obtuvimos no reveló ninguna correlación fuerte entre las posiciones planetarias y el precio de cierre del EURUSD. Todas nuestras correlaciones son inferiores a 0,3, lo que nos da motivos para creer que la posición de las estrellas o los planetas no está relacionada en absoluto con los mercados financieros.

Modelo de regresión CatBoost. Los resultados finales del modelo de regresión mostraron una capacidad muy pobre para predecir con precisión los precios de cierre futuros basándose en datos astronómicos.

Las métricas de rendimiento del modelo resultantes, como MSE, MAE y R cuadrado, son muy débiles y explican muy mal los datos. Al mismo tiempo, el modelo muestra que las características más importantes son los rezagos y los valores de precios anteriores, más que las posiciones planetarias. Entonces, ¿eso significa que el precio es un mejor indicador que la posición de cualquier planeta en nuestro sistema solar?

Modelo de clasificación CatBoost. El modelo de clasificación es extremadamente pobre a la hora de predecir futuras subidas o bajadas de precios. La precisión apenas supera el 50%, lo que también confirma que la astronomía no funciona en el mercado real.


Conclusión

Los resultados del estudio son bastante claros: los métodos de la astrología y los intentos de predecir los precios en el mercado real basándose en datos astronómicos son completamente inútiles. Quizás vuelva sobre este tema, pero por ahora las enseñanzas de William Gann parecen intentos de disfrazar soluciones que no funcionan, creadas únicamente para vender libros y cursos de trading.

¿Podría ser que un modelo mejorado que también utilizara los valores del ángulo de Gann, los valores del cuadrado de 9 y los valores de la cuadrícula de Gann funcionara mejor? Todavía no lo sabemos. Estoy un poco decepcionado con los resultados del estudio.

Pero sigo pensando que los ángulos de Gann se pueden utilizar de una forma u otra para obtener previsiones de precios funcionales. El precio afecta a los ángulos de una forma u otra, reacciona a ellos, lo cual es evidente a partir de los resultados del estudio anterior. También es posible que los ángulos se puedan utilizar como características de trabajo para los modelos de entrenamiento. Intentaré crear un conjunto de datos de este tipo y veré qué resulta. 

Traducción del ruso hecha por MetaQuotes Ltd.
Artículo original: https://www.mql5.com/ru/articles/15625

Archivos adjuntos |
GannAstroClass.py (9.39 KB)
AstroCorr.py (7.59 KB)
Maxim Kuznetsov
Maxim Kuznetsov | 29 ago 2024 en 11:51

Siguiendo los pasos de Ghana, en aras de la pureza de la experiencia, debería haber tomado no EURUSD, pero, por ejemplo, los futuros del algodón. Y el instrumento es aproximadamente el mismo y ciclos astronómicos puede estar en él, después de todo, la agricultura.

spalsule
spalsule | 10 mar 2025 en 07:19
Parece que no has estudiado los ciclos temporales de Gann. De ahí que pienses que no funciona. Funciona en todas las acciones y materias primas.
Algoritmo de Irrigación Artificial — Artificial Showering Algorithm (ASHA) Algoritmo de Irrigación Artificial — Artificial Showering Algorithm (ASHA)
Este artículo presenta el Algoritmo de Irrigación Artificial (ASHA), un nuevo método metaheurístico desarrollado para resolver problemas generales de optimización. Basado en la modelización de los procesos de flujo y almacenamiento del agua, este algoritmo construye el concepto de un campo ideal en el que cada unidad de recurso (agua) es invocada para encontrar una solución óptima. Hoy descubriremos cómo el ASHA adapta los principios de flujo y acumulación para asignar eficazmente los recursos en el espacio de búsqueda, y también veremos su aplicación y los resultados de sus pruebas.
Redes neuronales en el trading: Segmentación de datos basada en expresiones de referencia Redes neuronales en el trading: Segmentación de datos basada en expresiones de referencia
En el proceso de análisis de la situación del mercado, dividimos este en segmentos individuales, identificando las tendencias clave. Sin embargo, los métodos tradicionales de análisis suelen centrarse en un solo aspecto, lo cual limita nuestra percepción. En este artículo, presentaremos un método que nos permitirá seleccionar varios objetos, ofreciéndonos una comprensión más completa y variada de la situación.
Sistema de arbitraje de alta frecuencia en Python con MetaTrader 5 Sistema de arbitraje de alta frecuencia en Python con MetaTrader 5
Hoy vamos a crear un sistema de arbitraje legal a los ojos de los brókeres, que creará miles de precios sintéticos en el mercado Fórex, los analizará y negociará con éxito para obtener beneficios.
Ciclos y Forex Ciclos y Forex
Los ciclos son de gran importancia en nuestras vidas. El día y la noche, las estaciones, los días de la semana y muchos otros ciclos de distinta naturaleza están presentes en la vida de cualquier persona. En este artículo, consideraremos los ciclos en los mercados financieros.