diff --git a/.github/workflows/daily_update.yml b/.github/workflows/daily_update.yml index a6a866c..22b8c43 100644 --- a/.github/workflows/daily_update.yml +++ b/.github/workflows/daily_update.yml @@ -6,15 +6,15 @@ on: - cron: '0 21 * * 1-5' workflow_dispatch: # Bouton manuel -permissions: - contents: write - actions: read +# permissions: +# contents: write +# actions: read jobs: portfolio-optimization: - name: Run ML Pipeline & Update Portfolio + name: Run ML Pipeline & Sync to Hugging Face runs-on: ubuntu-latest - timeout-minutes: 15 + timeout-minutes: 20 steps: # ══════════════════════════════════════════════════════ @@ -33,8 +33,9 @@ jobs: - name: 📦 Install dependencies run: | - python -m pip install --upgrade pip setuptools wheel + python -m pip install --upgrade pip pip install -r requirements.txt + pip install huggingFace_hub datasets pyarrow # ══════════════════════════════════════════════════════ @@ -48,75 +49,17 @@ jobs: env: PYTHONUNBUFFERED: 1 TZ: Europe/Paris + HF_TOKEN: ${{ secrets.HF_TOKEN }} # ══════════════════════════════════════════════════════ - # 3. Verify Generated Files + # 3. Summary jobs # ══════════════════════════════════════════════════════ - - name: 🔍 Check generated files - run: | - echo "📂 Checking generated files..." - ls -lh latest_signals.csv portfolio_history.csv data_metadata.json || echo "Some output files missing" - - - # ══════════════════════════════════════════════════════ - # 4. Commit & Push Results (STRATÉGIE ANTI-CONFLIT) - # ══════════════════════════════════════════════════════ - - name: 💾 Commit updated data - run: | - git config --local user.name 'AlphaML Bot' - git config --local user.email '41898282+github-actions[bot]@users.noreply.github.com' - - # A. SAUVEGARDE TEMPORAIRE DES RÉSULTATS GÉNÉRÉS - # On met les nouveaux fichiers calculés à l'abri dans un dossier temporaire - mkdir -p /tmp/portfolio_data - cp latest_signals.csv /tmp/portfolio_data/ 2>/dev/null || true - cp portfolio_history.csv /tmp/portfolio_data/ 2>/dev/null || true - cp data_metadata.json /tmp/portfolio_data/ 2>/dev/null || true - cp debug_run.txt /tmp/portfolio_data/ 2>/dev/null || true - - # B. NETTOYAGE RADICAL (RESET) - # On s'assure d'être 100% aligné avec le serveur pour supprimer tout conflit fantôme - git fetch origin main - git reset --hard origin/main - - # C. RESTAURATION DES DONNÉES - # On ramène les fichiers frais calculés par le script - cp /tmp/portfolio_data/* . - - # D. PRÉPARATION DU COMMIT - # On ajoute uniquement les fichiers CSV/JSON (Pas de parquet !) - git add latest_signals.csv portfolio_history.csv data_metadata.json debug_run.txt - - # E. COMMIT ET PUSH - if ! git diff --staged --quiet; then - TIMESTAMP=$(date +'%Y-%m-%d %H:%M UTC') - git commit -m "chore(data): daily portfolio update ${TIMESTAMP}" - - # Pas besoin de pull complexe ici car on vient de faire un reset --hard - git push origin main - echo "✅ Data committed and pushed successfully" - else - echo "ℹ️ No changes to commit" - fi - - - # ══════════════════════════════════════════════════════ - # 5. Job Summary - # ══════════════════════════════════════════════════════ - - name: Generate job summary + - name: Generate job summary if: always() run: | - echo "## Portfolio Analytics Summary" >> $GITHUB_STEP_SUMMARY - echo "" >> $GITHUB_STEP_SUMMARY - echo "- **Date**: $(date +'%Y-%m-%d %H:%M UTC')" >> $GITHUB_STEP_SUMMARY + echo "## AlphaEdge Analytics Summary" >> $GITHUB_STEP_SUMMARY echo "- **Status**: ${{ job.status }}" >> $GITHUB_STEP_SUMMARY - echo "- **Run Number**: #${{ github.run_number }}" >> $GITHUB_STEP_SUMMARY - echo "" >> $GITHUB_STEP_SUMMARY - - if [ -f latest_signals.csv ]; then - echo "### Latest Signals (Top 5)" >> $GITHUB_STEP_SUMMARY - echo '```csv' >> $GITHUB_STEP_SUMMARY - head -n 6 latest_signals.csv >> $GITHUB_STEP_SUMMARY - echo '```' >> $GITHUB_STEP_SUMMARY - fi + echo "- **Data Provider**: Hugging Face (soradata/alphaedge-data)" >> $GITHUB_STEP_SUMMARY + echo "- **Market Timestamp**: $(date +'%Y-%m-%d %H:%M UTC')" >> $GITHUB_STEP_SUMMARY + \ No newline at end of file diff --git a/.gitignore b/.gitignore index 0152f7e..955bbdf 100644 --- a/.gitignore +++ b/.gitignore @@ -1,9 +1,11 @@ -# Fichiers de données générés et gros fichiers +# Generated outputs data/raw/ data/interim/ data/processed/ results/ - +data/*.parquet +data/metadata_*.json +data/ticker_validation.json # Fichiers Python/Jupyter/Environnement __pycache__/ @@ -33,5 +35,10 @@ logs/ .DS_Store .vscode/ *.swp +.env + +# Market configs not used yet +#config/nasdaq.json +#config/sp500.json diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..b63e5fe --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,41 @@ +# 🚀 Contribution Guide - AlphaEdge + +Thank you for contributing to **AlphaEdge**! To maintain a robust pipeline and stay true to industry standards (inspired by **Qlib**), please follow these guidelines. + +## 🌿 Branch Management + +The project uses a two-layer branch model to ensure pipeline stability: +* **`dev`**: The primary development branch. All new features (Alpha158, new models) and most bug fixes are merged here. +* **`main`**: The stable branch used for production deployments and Hugging Face dataset synchronization. + +## 🛠️ Development Workflow + +To contribute code: +1. **Fork**: Create a copy of the project on your GitHub account. +2. **Feature Branch**: Implement your changes in a specific branch within your fork. +3. **Respect Modularity**: + * **Signals**: New signal types (Models, Cache) must be implemented in `src/strategy/signals.py`. + * **Backtest**: Any changes regarding market friction, slippage, or execution logic belong in `src/pipeline/backtest.py`. + * **Features**: Integration of the 158 features (Alpha158) must be done in a vectorized manner to remain compatible with the `AlphaSignal` cache. + +## 🧪 Testing & Validation + +All changes must be validated before merging: +* **Unit Tests**: Run `python -m unittest discover -s tests`. +* **Realistic Backtest**: Ensure your changes do not introduce survivorship bias or ignore transaction costs (**Turnover Friction**). +* **Signal Cache**: Verify that the `AlphaSignal` object is correctly instantiated via its class method to prevent attribute errors. + +## 💡 Git Best Practices + +We aim to keep the commit history compact and readable: +* **Commit Messages**: Use a short summary followed by a detailed description if necessary (`git commit -m "feat: add alpha158" -m "detailed window description"`). +* **Squash**: Combine multiple small commits into a single clean commit before submitting a Pull Request. +* **Rebase**: Prefer `git rebase` to keep your branches up to date with the `dev` branch. + +## 📖 Documentation + +The project documentation is automatically generated from the code. If you modify a function, update its docstrings and check the documentation locally. + +--- + +**Questions?** Check the open issues on the repository or refer to the internal architecture guides in the `src/` directory. \ No newline at end of file diff --git a/__init__.py b/__init__.py index e69de29..51964cd 100644 --- a/__init__.py +++ b/__init__.py @@ -0,0 +1,14 @@ +from brvmfinance.tickers import Tickers + +# On définit les tickers (BOA Bénin, Mali, Sénégal, Côte d'Ivoire) +mes_actions = Tickers("BOAN BOAM BOAS BOAC") + +# Récupération de l'historique +df_global = mes_actions.history(length=7) # On prend un petit historique + +# Pour avoir "hier" (la dernière ligne de l'index temporel) +derniere_seance = df_global.index.max() +df_hier = df_global.loc[derniere_seance] + +print(f"📅 Données de la séance du : {derniere_seance}") +print(df_hier) \ No newline at end of file diff --git a/app.py b/app.py index 9a7861b..b12c858 100644 --- a/app.py +++ b/app.py @@ -1,32 +1,35 @@ -import streamlit as st -import pandas as pd -import plotly.express as px -import plotly.graph_objects as go -from plotly.subplots import make_subplots +import json +import os +import time from datetime import datetime, timedelta from pathlib import Path +from typing import Dict, Any + import numpy as np -import json +import pandas as pd +import plotly.graph_objects as go +import streamlit as st import yfinance as yf +from plotly.subplots import make_subplots from streamlit_autorefresh import st_autorefresh -import time + # ============================================================================= -# 1. CONFIGURATION & STYLE +# 1. PAGE CONFIG # ============================================================================= + st.set_page_config( page_title="AlphaEdge Dashboard", layout="wide", initial_sidebar_state="expanded" ) -# REFRESH AUTOMATIQUE (15 min) st_autorefresh(interval=900000, key="datarefresh") -# Chemins robustes pour la production BASE_DIR = Path(__file__).resolve().parent +CONFIG_DIR = BASE_DIR / "config" +HF_REPO_ID = os.getenv("HF_REPO_ID", "soradata/alphaedge-data") -# CSS Personnalisé st.markdown(""" """, unsafe_allow_html=True) + # ============================================================================= -# 2. CHARGEMENT DES DONNÉES (AVEC VALIDATION) +# 2. CONFIG LOADER # ============================================================================= -@st.cache_data(ttl=600, show_spinner=False) -def load_all_data(): - """Charge les CSVs avec validation complète""" - history_file = BASE_DIR / 'portfolio_history.csv' - signals_file = BASE_DIR / 'latest_signals.csv' - rebalance_file = BASE_DIR / 'rebalance_history.csv' - df_hist = pd.DataFrame() - df_signals = pd.DataFrame() - df_rebalance = pd.DataFrame() +def load_market_config(config_name: str) -> Dict[str, Any]: + target_path = CONFIG_DIR / config_name + fallback = { + "market_name": "Unknown Market", + "benchmark_ticker": "^GSPC", + "currency": "USD", + "assets": [] + } + + if not target_path.exists(): + return fallback + + try: + with open(target_path, "r", encoding="utf-8") as f: + return json.load(f) + except Exception: + return fallback + + +# ============================================================================= +# 3. CLOUD DATA LOADER +# ============================================================================= + +@st.cache_data(ttl=3600, show_spinner=False) +def load_all_data(config_filename: str): + suffix = config_filename.replace(".json", "") + base_url = f"https://huggingface.co/datasets/{HF_REPO_ID}/resolve/main/data" + errors = [] - # 1. Historique Portfolio - if history_file.exists(): - try: - df_hist = pd.read_csv(history_file, index_col=0) - df_hist.index = pd.to_datetime(df_hist.index, format='mixed', errors='coerce') - df_hist = df_hist[df_hist.index.notna()].sort_index(ascending=True) - if not df_hist.empty: - last_date = df_hist.index[-1] - days_old = (datetime.now() - last_date).days - if days_old > 7: - errors.append(f"⚠️ Portfolio data is {days_old} days old") - except Exception as e: - errors.append(f" Error loading portfolio history: {e}") - else: - errors.append(f" File not found: {history_file.name}") - # 2. Signaux - if signals_file.exists(): - try: - df_signals = pd.read_csv(signals_file) - required_cols = ['Ticker', 'Signal'] - missing = [c for c in required_cols if c not in df_signals.columns] - if missing: - errors.append(f" Missing columns in signals: {missing}") - except Exception as e: - errors.append(f" Error loading signals: {e}") - else: - errors.append(f"File not found: {signals_file.name}") - # 3. Rebalance history - if rebalance_file.exists(): + + def fetch_hf_parquet(file_prefix: str) -> pd.DataFrame: + url = f"{base_url}/{file_prefix}_{suffix}.parquet" try: - df_rebalance = pd.read_csv(rebalance_file, index_col=0) - df_rebalance.index = pd.to_datetime(df_rebalance.index).sort_values() - except Exception as e: - errors.append(f" Could not load rebalance history: {e}") - return df_hist, df_signals, df_rebalance, errors + return pd.read_parquet(url) + except Exception: + errors.append(f"Impossible de charger {file_prefix}_{suffix}.parquet depuis HF") + return pd.DataFrame() + + df_hist = fetch_hf_parquet("portfolio_history") + if not df_hist.empty: + df_hist.index = pd.to_datetime(df_hist.index, errors="coerce") + df_hist = df_hist[df_hist.index.notna()].sort_index(ascending=True) + df_signals = fetch_hf_parquet("latest_signals") + + df_rebalance = fetch_hf_parquet("rebalance_history") + if not df_rebalance.empty: + df_rebalance.index = pd.to_datetime(df_rebalance.index, errors="coerce") + df_rebalance = df_rebalance[df_rebalance.index.notna()].sort_index(ascending=False) + + return df_hist, df_signals, df_rebalance, errors -with st.spinner("Loading data..."): - df_hist, df_signals, df_rebalance, load_errors = load_all_data() # ============================================================================= -# 3. FONCTIONS UTILITAIRES +# 4. KPI + METRICS # ============================================================================= - def display_kpi_card(label, value, is_percent=True, color_code=False, prefix="", minimal=False): - """KPI Card avec gestion robuste des valeurs NaN/Inf""" if pd.isna(value) or np.isinf(value): html_val = 'N/A' else: @@ -133,147 +157,149 @@ def display_kpi_card(label, value, is_percent=True, color_code=False, prefix="", html_val = f'{arrow} {formatted_val}' else: html_val = f'{formatted_val}' + css_class = "kpi-minimal" if minimal else "kpi-container" - st.markdown(f""" -
-
{label}
- {html_val} -
- """, unsafe_allow_html=True) + st.markdown( + f'
{label}
{html_val}
', + unsafe_allow_html=True + ) -def calculate_metrics(df): - """Calcul métriques avec validation edge cases""" +def calculate_metrics(df: pd.DataFrame): if df.empty or len(df) < 2: - return 0, 0, 0, 0 + return 0.0, 0.0, 0.0, 0.0 + try: - total_ret = (df['Strategy'].iloc[-1] / df['Strategy'].iloc[0]) - 1 - bench_ret = (df['Benchmark'].iloc[-1] / df['Benchmark'].iloc[0]) - 1 - alpha = total_ret - bench_ret - strategy_returns = df['Strategy'].pct_change().dropna() - sharpe = (strategy_returns.mean() / strategy_returns.std()) * np.sqrt(252) if len(strategy_returns) > 0 and strategy_returns.std() != 0 else 0 + total_ret = (df["Strategy"].iloc[-1] / df["Strategy"].iloc[0]) - 1 + bench_ret = (df["Benchmark"].iloc[-1] / df["Benchmark"].iloc[0]) - 1 + alpha = total_ret - bench_ret + + strategy_returns = df["Strategy"].pct_change().dropna() + sharpe = ( + (strategy_returns.mean() / strategy_returns.std()) * np.sqrt(252) + if strategy_returns.std() != 0 else 0.0 + ) + cum_ret = (1 + strategy_returns).cumprod() max_dd = ((cum_ret - cum_ret.cummax()) / cum_ret.cummax()).min() + return total_ret, alpha, sharpe, max_dd except Exception: - return 0, 0, 0, 0 + return 0.0, 0.0, 0.0, 0.0 -def calculate_period_return(df, days=None, ytd=False, daily=False): - """Calcul rendements par période""" - if df.empty or 'Strategy' not in df.columns or len(df) < 2: +def calculate_period_return(df: pd.DataFrame, days=None, ytd=False, daily=False): + if df.empty or "Strategy" not in df.columns or len(df) < 2: return 0.0 + try: if daily: - return (df['Strategy'].iloc[-1] / df['Strategy'].iloc[-2]) - 1 - last_price, last_date = df['Strategy'].iloc[-1], df.index[-1] + return (df["Strategy"].iloc[-1] / df["Strategy"].iloc[-2]) - 1 + + last_price = df["Strategy"].iloc[-1] + last_date = df.index[-1] + if ytd: target_date = datetime(last_date.year, 1, 1) elif days: target_date = last_date - timedelta(days=days) else: target_date = df.index[0] - if target_date < df.index[0]: - start_price = df['Strategy'].iloc[0] - else: - start_price = df['Strategy'].iloc[df.index.get_indexer([target_date], method='nearest')[0]] + + idx = df.index.get_indexer([pd.Timestamp(target_date)], method="nearest")[0] + start_price = df["Strategy"].iloc[idx] + return ((last_price / start_price) - 1) if start_price != 0 else 0.0 + except Exception: return 0.0 @st.cache_data(ttl=3600) -def get_live_ticker_data(ticker, period="1y"): - """Télécharge données yfinance avec RETRY mechanism""" - for _ in range(3): +def get_live_ticker_data(ticker: str, period: str = "1y") -> pd.DataFrame: + for _ in range(2): try: df = yf.download(ticker, period=period, progress=False, timeout=10) if not df.empty: - df.columns = df.columns.get_level_values(0) if isinstance(df.columns, pd.MultiIndex) else df.columns + if isinstance(df.columns, pd.MultiIndex): + df.columns = df.columns.get_level_values(0) df.columns = df.columns.str.lower() - if 'adj close' not in df.columns and 'close' in df.columns: - df['adj close'] = df['close'] + + if "adj close" not in df.columns and "close" in df.columns: + df["adj close"] = df["close"] + return df - time.sleep(2) except Exception: - time.sleep(2) + time.sleep(1) + return pd.DataFrame() + # ============================================================================= -# 4. SIDEBAR +# 5. SIDEBAR # ============================================================================= - st.sidebar.title("AlphaEdge") st.sidebar.caption("Quantitative Asset Allocation") -if st.sidebar.button("🔄 Force Sync Pipeline"): +available_configs = ( + sorted([f for f in os.listdir(CONFIG_DIR) if f.endswith(".json")]) + if CONFIG_DIR.exists() else [] +) + +if not available_configs: + st.sidebar.error("No configuration files found in /config") + st.stop() + +selected_config = st.sidebar.selectbox( + "Market Selection", + available_configs, + index=available_configs.index("cac40.json") if "cac40.json" in available_configs else 0 +) + +MARKET_CONFIG = load_market_config(selected_config) +CURRENCY_SYMBOL = "€" if MARKET_CONFIG.get("currency") == "EUR" else "$" + +with st.sidebar: + with st.spinner(f"Fetching {MARKET_CONFIG.get('market_name')} data from Cloud..."): + df_hist, df_signals, df_rebalance, load_errors = load_all_data(selected_config) + +if st.sidebar.button("Force Sync Pipeline"): st.cache_data.clear() st.rerun() st.sidebar.markdown( - f"[![GitHub](https://img.shields.io/badge/GITHUB-Source_Code-181717?style=for-the-badge&logo=github&logoColor=white)](https://github.com/SORADATA/CAC40-Quantitative-Analysis-Predictive-Asset-Allocation)" - ) + "[![GitHub](https://img.shields.io/badge/GITHUB-Source_Code-181717?style=for-the-badge&logo=github&logoColor=white)](https://github.com/SORADATA/CAC40-Quantitative-Analysis-Predictive-Asset-Allocation)" +) + +page = st.sidebar.radio( + "Navigation", + ["Dashboard", "Daily Signals", "Data Explorer", "Model Details", "Rebalance History"] +) -st.sidebar.markdown("---") -page = st.sidebar.radio("Navigation", [ - "Dashboard", - "Daily Signals", - "Data Explorer", - "Model Details", - "Rebalance History" -]) -st.sidebar.markdown("---") - -# STATUS INDICATOR if not df_hist.empty: last_dt = df_hist.index[-1] - days_old = (datetime.now() - last_dt).days - status_icon, status_text = ("🟢", "● System Online") if days_old == 0 else ("🟡", "○ Data Slightly Old") if days_old <= 3 else ("🔴", "○ Data Outdated") - st.sidebar.info(f"Last Update: {last_dt.date() if hasattr(last_dt, 'date') else str(last_dt).split(' ')[0]}") - st.sidebar.markdown(f"{status_icon} {status_text}") -else: - st.sidebar.error(" No Data Available") - -st.sidebar.markdown("---") - -# TICKER HEALTH -ticker_val_path = BASE_DIR / 'ticker_validation.json' -if ticker_val_path.exists(): - with st.sidebar.expander("🔍 Ticker Health", expanded=False): - try: - with open(ticker_val_path, 'r') as f: - validation = json.load(f) - alerts = validation.get('alerts', {}) - - if alerts.get('delisted'): - st.error(f"{len(alerts['delisted'])} delistés") - if alerts.get('stale'): - st.warning(f"⚠️ {len(alerts['stale'])} obsolètes") - if alerts.get('warnings'): - st.info(f"ℹ️ {len(alerts['warnings'])} warnings") - st.metric("Valid Tickers", validation.get('valid_tickers', 0)) - except Exception: - st.caption("Validation data unavailable") - -st.sidebar.markdown("---") + st.sidebar.info(f"Last Update: {last_dt.date()}") + st.sidebar.markdown( + "🟢 Cloud Sync: Active" if (datetime.now() - last_dt).days <= 1 else "🔴 Update Required" + ) -# DATA ISSUES if load_errors: - with st.sidebar.expander(" Data Issues", expanded=False): + with st.sidebar.expander("Cloud Sync Issues", expanded=False): for err in load_errors: - st.warning(err, icon="⚠️") + st.warning(err) -st.sidebar.caption("⚠️ **Disclaimer:** Not financial advice.") # ============================================================================= -# PAGE 1 : DASHBOARD +# 6. PAGES # ============================================================================= if page == "Dashboard": - st.title(" Portfolio Overview") + st.title(f"Portfolio Overview: {MARKET_CONFIG.get('market_name')}") + if not df_hist.empty: tot_ret, alpha, sharpe, max_dd = calculate_metrics(df_hist) + c1, c2, c3, c4 = st.columns(4) with c1: display_kpi_card("Total Return", tot_ret, color_code=True) @@ -283,337 +309,181 @@ def get_live_ticker_data(ticker, period="1y"): display_kpi_card("Sharpe Ratio", sharpe, is_percent=False) with c4: display_kpi_card("Max Drawdown", max_dd, color_code=True) + st.markdown("
", unsafe_allow_html=True) - st.subheader("Period Performance") + k1, k2, k3, k4, k5 = st.columns(5) with k1: - display_kpi_card( - "YTD", - calculate_period_return(df_hist, ytd=True), - color_code=True, minimal=True - ) + display_kpi_card("YTD", calculate_period_return(df_hist, ytd=True), color_code=True, minimal=True) with k2: - display_kpi_card( - "6 Months", - calculate_period_return(df_hist, days=180), - color_code=True, minimal=True - ) + display_kpi_card("6 Months", calculate_period_return(df_hist, days=180), color_code=True, minimal=True) with k3: - display_kpi_card( - "3 Months", - calculate_period_return(df_hist, days=90), - color_code=True, minimal=True) + display_kpi_card("3 Months", calculate_period_return(df_hist, days=90), color_code=True, minimal=True) with k4: - display_kpi_card( - "1 Month", - calculate_period_return(df_hist, days=30), - color_code=True, minimal=True) + display_kpi_card("1 Month", calculate_period_return(df_hist, days=30), color_code=True, minimal=True) with k5: - display_kpi_card( - "Daily Return", - calculate_period_return(df_hist, daily=True), - color_code=True, minimal=True - ) - st.markdown("---") - col_title, col_filter = st.columns([2, 1]) - with col_title: - st.subheader("Strategy vs Benchmark") - with col_filter: - p_sel = st.radio( - "Zoom:", - ["1M", "3M", "6M", "YTD", "1Y", "ALL"], - index=5, horizontal=True, label_visibility="collapsed" - ) - df_c = df_hist.copy() - end = df_c.index[-1] - if p_sel == "1M": - start = end - timedelta(days=30) - elif p_sel == "3M": - start = end - timedelta(days=90) - elif p_sel == "6M": - start = end - timedelta(days=180) - elif p_sel == "YTD": - start = datetime(end.year, 1, 1) - elif p_sel == "1Y": - start = end - timedelta(days=365) - else: - start = df_c.index[0] - if start < df_c.index[0]: - start = df_c.index[0] - df_c = df_c[df_c.index >= pd.Timestamp(start)] - df_base = df_c.apply(lambda x: x / x.iloc[0] * 100) + display_kpi_card("Daily", calculate_period_return(df_hist, daily=True), color_code=True, minimal=True) + + df_base = df_hist.apply(lambda x: x / x.iloc[0] * 100) + fig = go.Figure() fig.add_trace( go.Scatter( x=df_base.index, - y=df_base['Strategy'], - mode='lines', name='Hybrid Strategy', line=dict(color='#00CC96', width=2.5), - fill='tonexty', fillcolor='rgba(0, 204, 150, 0.1)' - )) + y=df_base["Strategy"], + name="Strategy", + line=dict(color="#00CC96", width=2), + fill="tonexty", + fillcolor="rgba(0, 204, 150, 0.1)" + ) + ) fig.add_trace( go.Scatter( - x=df_base.index, y=df_base['Benchmark'], - mode='lines', name='Benchmark', line=dict(color='#8b92a5', width=1.5, dash='dash') - )) + x=df_base.index, + y=df_base["Benchmark"], + name="Benchmark", + line=dict(color="#8b92a5", width=1, dash="dash") + ) + ) + fig.update_layout( template="plotly_dark", + height=450, margin=dict(l=0, r=0, t=10, b=0), - height=400, hovermode="x unified", - legend=dict(orientation="h", y=1.02, x=1, xanchor="right"), - yaxis_title="Indexed Value (Base 100)" - ) + hovermode="x unified" + ) st.plotly_chart(fig, use_container_width=True) - st.markdown("---") - c_risk, c_pie = st.columns([3, 2]) - with c_risk: - st.subheader("⚠️ Risk Analysis") - s_ret = df_c['Strategy'].pct_change().dropna() - cum = (1 + s_ret).cumprod() - dd = (cum - cum.cummax()) / cum.cummax() - fig_dd = go.Figure() - fig_dd.add_trace( - go.Scatter( - x=dd.index, y=dd, fill='tozeroy', mode='lines', - line=dict(color='#EF553B', width=1.5), - name='Drawdown', fillcolor='rgba(239, 85, 59, 0.3)' - )) - fig_dd.update_layout( - template="plotly_dark", - margin=dict(l=0, r=0, t=10, b=0), - height=320, yaxis_tickformat='.1%', yaxis_title="Drawdown" - ) - st.plotly_chart(fig_dd, use_container_width=True) - with c_pie: - st.subheader("Current Allocation") - if not df_signals.empty and 'Allocation' in df_signals.columns: - active = df_signals[df_signals['Allocation'] > 0.001].copy() - cash = max(0, 1.0 - active['Allocation'].sum()) - if cash > 0.001: - final = pd.concat( - [active, pd.DataFrame([{'Ticker': 'CASH', 'Allocation': cash}])], - ignore_index=True) - else: - final = active - fig_p = px.pie( - final, values='Allocation', names='Ticker', - hole=0.5, color_discrete_sequence=px.colors.qualitative.Prism - ) - fig_p.update_traces(textposition='outside', textinfo='percent+label') - fig_p.update_layout( - template="plotly_dark", - margin=dict(l=20, r=20, t=0, b=0), showlegend=False, height=370 - ) - st.plotly_chart(fig_p, use_container_width=True) - else: - st.info("⏳ Waiting for signals...") + else: - st.warning("⚠️ No data. Run `python daily_run.py`") + st.error("No historical data found in the Cloud for this market. Please run the daily pipeline.") -# ============================================================================= -# PAGE 2 : DAILY SIGNALS -# ============================================================================= elif page == "Daily Signals": - st.title("📡 Daily Trading Signals") + st.title(f"📡 Trading Signals: {MARKET_CONFIG.get('market_name')}") + if not df_signals.empty: - d = df_signals.copy() - if 'Allocation' in d.columns: - d = d.sort_values('Allocation', ascending=False) - col_filter1, col_filter2 = st.columns([1, 3]) - with col_filter1: - filter_opt = st.selectbox("Filter", ["All Signals", "BUY Only", "NEUTRAL Only"]) - if filter_opt == "BUY Only": - d = d[d['Signal'] == 'BUY'] - elif filter_opt == "NEUTRAL Only": - d = d[d['Signal'] == 'NEUTRAL'] st.dataframe( - d, use_container_width=True, height=600, hide_index=True, + df_signals, + use_container_width=True, + height=600, + hide_index=True, column_config={ "Allocation": st.column_config.ProgressColumn( "Weight", format="%.2f", min_value=0, max_value=1 - ), - "Proba_Hausse": st.column_config.NumberColumn("Probability ↑", format="%.1f%%") + ), + "Proba_Hausse": st.column_config.NumberColumn( + "Probability ↑", format="%.1f%%" + ) } ) - st.markdown("---") - col_s1, col_s2, col_s3 = st.columns(3) - with col_s1: - st.metric("Total Tickers", len(df_signals)) # Fix : compte total original - with col_s2: - # THE FIX: Explicitly count 'BUY' strings in the Signal column - n_buy = len( - df_signals[df_signals['Signal'] == 'BUY']) if 'Signal' in df_signals.columns else 0 - st.metric("BUY Signals", n_buy) - with col_s3: - alloc_total = df_signals['Allocation'].sum() if 'Allocation' in df_signals.columns else 0 - st.metric("Total Allocated", f"{alloc_total:.1%}") else: - st.info("⏳ No signals. Run pipeline first.") + st.info("No active signals found for this selection.") -# ============================================================================= -# PAGE 3 : DATA EXPLORER -# ============================================================================= elif page == "Data Explorer": st.title("🔎 Market Data Explorer") - default_tickers = ["AI.PA", "AIR.PA", "BNP.PA", "MC.PA", "OR.PA", "TTE.PA"] - tickers = df_signals['Ticker'].unique().tolist() if not df_signals.empty and 'Ticker' in df_signals.columns else default_tickers - col_sel1, col_sel2 = st.columns([1, 3]) - with col_sel1: - selected_ticker = st.selectbox("Select Asset", tickers, index=0) - with col_sel2: - period_exp = st.selectbox( - "Timeframe", - ["1 Month", "3 Months", "6 Months", "1 Year", "5 Years"], index=2 + + config_tickers = MARKET_CONFIG.get("assets", []) + signal_tickers = df_signals["Ticker"].unique().tolist() if (not df_signals.empty and "Ticker" in df_signals.columns) else [] + final_tickers = sorted(list(set(config_tickers + signal_tickers))) + + if final_tickers: + selected_ticker = st.selectbox("Select Asset", final_tickers) + + with st.spinner("Downloading live data..."): + df_asset = get_live_ticker_data(selected_ticker) + + if not df_asset.empty: + m1, m2 = st.columns(2) + last_price = df_asset["adj close"].iloc[-1] + daily_var = (last_price / df_asset["adj close"].iloc[-2]) - 1 if len(df_asset) > 1 else 0 + + with m1: + display_kpi_card("Last Price", last_price, is_percent=False, prefix=f"{CURRENCY_SYMBOL} ") + with m2: + display_kpi_card("Daily Change", daily_var, color_code=True) + + fig = make_subplots( + rows=2, + cols=1, + shared_xaxes=True, + vertical_spacing=0.05, + row_heights=[0.7, 0.3] ) - yf_period_map = { - "1 Month": "1mo", "3 Months": "3mo", "6 Months": "6mo", "1 Year": "1y", "5 Years": "5y" - } - with st.spinner(f" Downloading {selected_ticker}..."): - df_asset = get_live_ticker_data(selected_ticker, period=yf_period_map[period_exp]) - if not df_asset.empty and len(df_asset) > 1: - try: - last_close = df_asset['adj close'].iloc[-1] - prev_close = df_asset['adj close'].iloc[-2] - daily_var = (last_close / prev_close) - 1 - first_p = df_asset['adj close'].iloc[0] - total_ret_period = (last_close / first_p) - 1 if first_p != 0 else 0 - ret_series = df_asset['adj close'].pct_change().dropna() - volatility = ret_series.std() * np.sqrt(252) if not ret_series.empty else 0 - except Exception: - last_close = daily_var = total_ret_period = volatility = 0 - m1, m2, m3, m4 = st.columns(4) - with m1: - display_kpi_card("Last Price", last_close, is_percent=False, prefix="€ ") - with m2: - display_kpi_card("Daily Change", daily_var, color_code=True) - with m3: - display_kpi_card(f"Return ({period_exp})", total_ret_period, color_code=True) - with m4: - display_kpi_card("Ann. Volatility", volatility, is_percent=True) - st.subheader(f"Price Action: {selected_ticker}") - fig = make_subplots( - rows=2, cols=1, shared_xaxes=True, vertical_spacing=0.05, row_heights=[0.7, 0.3] + + fig.add_trace( + go.Candlestick( + x=df_asset.index, + open=df_asset["open"], + high=df_asset["high"], + low=df_asset["low"], + close=df_asset["close"], + name="Price" + ), + row=1, + col=1 ) - fig.add_trace( - go.Candlestick( - x=df_asset.index, open=df_asset['open'], - high=df_asset['high'], - low=df_asset['low'], - close=df_asset['close'], - name='OHLC'), row=1, col=1) - colors = [ - '#00CC96' if r >= 0 else '#EF553B' for r in df_asset['adj close'].pct_change().fillna(0) - ] - fig.add_trace( - go.Bar( - x=df_asset.index, y=df_asset['volume'], - name='Volume', marker_color=colors - ), row=2, col=1) - fig.update_layout( - template="plotly_dark", xaxis_rangeslider_visible=False, height=550, - margin=dict(l=0, r=0, t=30, b=0), showlegend=False) - st.plotly_chart(fig, use_container_width=True) + + fig.add_trace( + go.Bar( + x=df_asset.index, + y=df_asset["volume"], + name="Volume", + marker_color="#8b92a5" + ), + row=2, + col=1 + ) + + fig.update_layout( + template="plotly_dark", + xaxis_rangeslider_visible=False, + height=600, + margin=dict(l=0, r=0, t=30, b=0) + ) + st.plotly_chart(fig, use_container_width=True) + else: - st.warning(f"⚠️ No data for {selected_ticker}") + st.warning("No tickers available to explore.") -# ============================================================================= -# PAGE 4 : MODEL DETAILS -# ============================================================================= elif page == "Model Details": st.title("⚙️ Model Configuration") - tab1, tab2 = st.tabs(["📊 Performance", "🌐 Clusters"]) - with tab1: - st.markdown(""" - ### Hybrid Strategy Components - **1. XGBoost**: Predicts 1-month upside probability - **2. K-Means**: Market regime detection (RSI-based) - **3. Markowitz**: Portfolio optimization (Max Sharpe) - """) - st.markdown("---") - metrics_path = BASE_DIR / "src" / "models" / "metrics.json" - if metrics_path.exists(): + st.info("Architecture: XGBoost (Prediction) + K-Means (Regime) + Top-k (Portfolio Construction)") + + metrics_path = BASE_DIR / "src" / "models" / "metrics.json" + + if metrics_path.exists(): + with open(metrics_path, "r", encoding="utf-8") as f: try: - with open(metrics_path, "r") as f: - metrics = json.load(f) - st.markdown("### Model Performance (Test Set)") - col1, col2, col3, col4 = st.columns(4) - with col1: - st.metric("Accuracy", f"{metrics.get('accuracy', 0):.2%}") - with col2: - st.metric("Precision", f"{metrics.get('precision', 0):.2%}") - with col3: - st.metric("Recall", f"{metrics.get('recall', 0):.2%}") - with col4: - st.metric("ROC AUC", f"{metrics.get('auc_score', 0):.4f}") + m = json.load(f) + c1, c2, c3 = st.columns(3) + c1.metric("Accuracy", f"{m.get('accuracy', 0):.1%}") + c2.metric("Precision", f"{m.get('precision', 0):.1%}") + c3.metric("ROC AUC", f"{m.get('auc_score', 0):.3f}") except Exception: - st.info("⏳ Metrics unreadable.") - else: - st.info("⏳ Metrics not available. Train model first.") - with tab2: - st.subheader("🌐 Cluster Analysis") - st.markdown("Segmentation based on RSI to identify momentum vs reversal regimes.") - if not df_signals.empty and 'RSI' in df_signals.columns and 'Return_3M' in df_signals.columns: - fig = px.scatter( - df_signals, x="RSI", y="Return_3M", color="Cluster", hover_name="Ticker", - color_continuous_scale=px.colors.sequential.Viridis, - labels={"RSI": "RSI (20)", "Return_3M": "3-Month Momentum"} - ) - fig.update_layout(template="plotly_dark", height=500) - st.plotly_chart(fig, use_container_width=True) - else: - st.warning("⚠️ No cluster data available") + st.error("Metrics file corrupted.") + else: + st.warning("Training metrics not found. Please train models to see results.") -# ============================================================================= -# PAGE 5 : REBALANCE HISTORY -# ============================================================================= elif page == "Rebalance History": - st.title(" Monthly Rebalancing History") + st.title(f"📅 Rebalancing Log: {MARKET_CONFIG.get('market_name')}") + if not df_rebalance.empty: - st.markdown(""" - This page shows the **monthly rebalancing decisions** made by the strategy. - Each month, the model selects new assets and recalculates optimal weights. - """) - col_r1, col_r2, col_r3 = st.columns(3) - with col_r1: - st.metric("Total Rebalances", len(df_rebalance)) - with col_r2: - avg_stocks = df_rebalance['N_Stocks'].mean() if 'N_Stocks' in df_rebalance.columns else 0 - st.metric("Avg. Stocks/Month", f"{avg_stocks:.1f}") - with col_r3: - last_rebal = df_rebalance.index[-1].date() if len(df_rebalance) > 0 else "N/A" - st.metric("Last Rebalance", str(last_rebal)) - st.markdown("---") - if 'N_Stocks' in df_rebalance.columns: - st.subheader(" Portfolio Size Evolution") - fig = go.Figure() - fig.add_trace( - go.Scatter( - x=df_rebalance.index, - y=df_rebalance['N_Stocks'], - mode='lines+markers', name='N° Stocks', - line=dict(color='#00CC96', width=2), marker=dict(size=6))) - fig.update_layout( - template="plotly_dark", - height=350, yaxis_title="Number of Stocks", xaxis_title="Date") - st.plotly_chart(fig, use_container_width=True) - st.subheader(" Detailed Rebalancing Log") - st.dataframe(df_rebalance, use_container_width=True, height=400) + st.dataframe(df_rebalance, use_container_width=True) else: - st.info("⏳ No rebalance history. Run the corrected pipeline first.") + st.info("No rebalancing history recorded for this market.") + # ============================================================================= -# DISCLAIMER FOOTER +# 7. FOOTER # ============================================================================= st.markdown("---") st.markdown("""
⚠️ AVIS DE NON-RESPONSABILITÉ
-

Les informations présentées sur ce tableau de bord sont fournies à titre informatif et éducatif uniquement. Elles ne constituent en aucun cas un conseil en investissement.

-

Risques : Tout investissement comporte des risques. Les performances passées ne garantissent pas les résultats futurs.

-

Responsabilité : Consultez un conseiller financier agréé avant toute décision d'investissement.

+

Les informations présentées sont fournies à titre indicatif et éducatif. Elles ne constituent pas un conseil financier.

-""", unsafe_allow_html=True) +""", unsafe_allow_html=True) \ No newline at end of file diff --git a/config/backtest_config.yaml b/config/backtest_config.yaml new file mode 100644 index 0000000..f3d9e8b --- /dev/null +++ b/config/backtest_config.yaml @@ -0,0 +1,44 @@ +backtest: + start_time: "2020-01-01" + end_time: null # dynamique : today en production + mode: "live" # basculer sur "backtest" pour évaluation historique + initial_capital: 100.0 # base indice pour comparaison normalisée + risk_free_rate: 0.02 + trading_days_year: 252 + +transaction: + open_cost: 0.0005 + close_cost: 0.0015 + min_cost: 0.0 + +strategy: + method: "topk" + target_cluster: 3 + proba_threshold: 0.55 + weight_bounds: [0.02, 0.25] + lookback_days: 252 + feature_cols: + - rsi + - macd + - bb_low + - bb_high + - atr + - return_2m + - return_3m + - return_6m + - euro_volume_lag1 + - garman_klass_vol_lag1 + - Mkt-RF_lag1 + - SMB_lag1 + - HML_lag1 + - RMW_lag1 + - CMA_lag1 + - cluster + +benchmark: + ticker: "^FCHI" # CAC40 + +pipeline: + run_daily: true + rebalance_frequency: "monthly" # le backtest rebalance mensuellement + signal_cache: true diff --git a/config/brvm.json b/config/brvm.json new file mode 100644 index 0000000..ec9d667 --- /dev/null +++ b/config/brvm.json @@ -0,0 +1,18 @@ +{ + "market_name": "BRVM (UEMOA)", + "benchmark_ticker": "BRVM_COMPOSITE", + "currency": "XOF", + "assets": [ + "ABJC", "BICC", "BNBC", "BOAC", "CABC", "CFAC", "CIEC", + "ECOC", "FTSC", "NEIC", "NSBC", "NTLC", "ORAC", "PALC", + "PRSC", "SAFC", "SCRC", "SDCC", "SDSC", "SEMC", "SGBC", + "SHEC", "SIBC", "SICC", "SIVC", "SLBC", "SMBC", "SOGC", + "SPHC", "STAC", "STBC", "TTLC", "UNLC", "UNXC", + "BOAS", "SNTS", "TTLS", + "BOABF", "CBIBF", "ONTBF", + "BOAM", + "ETIT", "ORGT", + "BICB", "LNBB", "BOAB", + "BOAN" + ] +} \ No newline at end of file diff --git a/config/market_config.json b/config/cac40.json similarity index 100% rename from config/market_config.json rename to config/cac40.json diff --git a/const.py b/const.py index c9a0db9..6929922 100644 --- a/const.py +++ b/const.py @@ -1,72 +1,86 @@ from pathlib import Path - - -# ============================================================================= -# PATHS -# ============================================================================= +import os +from datetime import date +from dotenv import load_dotenv +import yaml BASE_DIR = Path(__file__).resolve().parent -DATA_DIR = BASE_DIR / "data" -MODEL_DIR = BASE_DIR / 'src' / 'models' -LOG_DIR = BASE_DIR / "logs" -CONFIG_FILE = BASE_DIR / "config" / "market_config.json" +CONFIG_PATH = BASE_DIR / "config" / "backtest_config.yaml" -# ============================================================================= -# MARKET & RISK -# ============================================================================= +load_dotenv(BASE_DIR / ".env") -TRADING_DAYS_YEAR: int = 252 -RISK_FREE_RATE: float = 0.03 +with open(CONFIG_PATH, "r", encoding="utf-8") as f: + cfg = yaml.safe_load(f) or {} -# ============================================================================= -# ML SIGNAL -# ============================================================================= +backtest_cfg = cfg.get("backtest", {}) +strategy_cfg = cfg.get("strategy", {}) +transaction_cfg = cfg.get("transaction", {}) +huggingface_cfg = cfg.get("huggingface", {}) -TARGET_CLUSTER: int = 3 -PROBA_THRESHOLD: float = 0.6 - -FEATURE_COLS: list[str] = [ - "rsi", - "macd", - "bb_low", - "bb_high", - "atr", - "return_2m", - "return_3m", - "return_6m", - "euro_volume_lag1", - "garman_klass_vol_lag1", - "Mkt-RF_lag1", - "SMB_lag1", - "HML_lag1", - "RMW_lag1", - "CMA_lag1", - "cluster", -] +DATA_DIR = BASE_DIR / "data" +MODEL_DIR = BASE_DIR / "src" / "models" +LOG_DIR = BASE_DIR / "logs" +CONFIG_DIR = BASE_DIR / "config" + +DEFAULT_MARKET = "cac40.json" +CONFIG_FILE = CONFIG_DIR / DEFAULT_MARKET + +RISK_FREE_RATE = backtest_cfg.get("risk_free_rate", 0.02) +TRADING_DAYS_YEAR = backtest_cfg.get("trading_days_year", 252) +END_TIME = backtest_cfg.get("end_time") or date.today().strftime("%Y-%m-%d") + +FEE_BPS = transaction_cfg.get("fee_bps", 0.003) + +HF_TOKEN = os.getenv("HF_TOKEN") +REPO_ID = huggingface_cfg.get("repo_id", "soradata/alphaedge-data") + +TARGET_CLUSTER = strategy_cfg.get("target_cluster", 3) +PROBA_THRESHOLD = strategy_cfg.get("proba_threshold", 0.6) +FEATURE_COLS = strategy_cfg.get( + "feature_cols", + [ + "rsi", + "macd", + "bb_low", + "bb_high", + "atr", + "return_2m", + "return_3m", + "return_6m", + "euro_volume_lag1", + "garman_klass_vol_lag1", + "Mkt-RF_lag1", + "SMB_lag1", + "HML_lag1", + "RMW_lag1", + "CMA_lag1", + "cluster", + ], +) # ============================================================================= # TECHNICAL INDICATORS # ============================================================================= -RSI_WINDOW: int = 20 -BB_WINDOW: int = 20 -BB_STD: int = 2 -ATR_WINDOW: int = 14 -MACD_SLOW: int = 26 -MACD_FAST: int = 12 -MACD_SIGN: int = 9 +RSI_WINDOW = 20 +BB_WINDOW = 20 +BB_STD = 2 +ATR_WINDOW = 14 +MACD_SLOW = 26 +MACD_FAST = 12 +MACD_SIGN = 9 # ============================================================================= # FEATURE ENGINEERING # ============================================================================= -MIN_HISTORY_TA: int = 20 # minimum bars for RSI / Bollinger -MIN_HISTORY_FF: int = 24 # minimum bars for Fama-French rolling betas +MIN_HISTORY_TA = 20 +MIN_HISTORY_FF = 24 -MOMENTUM_LAGS: list[int] = [1, 2, 3, 6, 9, 12] -WINSOR_CUTOFF: float = 0.005 +MOMENTUM_LAGS = [1, 2, 3, 6, 9, 12] +WINSOR_CUTOFF = 0.005 -VARS_TO_LAG: list[str] = [ +VARS_TO_LAG = [ "Mkt-RF", "SMB", "HML", @@ -76,19 +90,19 @@ "garman_klass_vol", ] -FAMA_FRENCH_FACTORS: list[str] = ["Mkt-RF", "SMB", "HML", "RMW", "CMA"] +FAMA_FRENCH_FACTORS = ["Mkt-RF", "SMB", "HML", "RMW", "CMA"] # ============================================================================= # RESAMPLING # ============================================================================= -RESAMPLE_MEAN_COLS: list[str] = ["euro_volume"] +RESAMPLE_MEAN_COLS = ["euro_volume"] -RESAMPLE_LAST_EXCLUDE: list[str] = [ +RESAMPLE_LAST_EXCLUDE = [ "euro_volume", "volume", "open", "high", "low", "close", -] +] \ No newline at end of file diff --git a/daily_run.py b/daily_run.py index 22beaa5..3a254cb 100644 --- a/daily_run.py +++ b/daily_run.py @@ -1,103 +1,257 @@ -import sys +import io import json +import os import warnings -from datetime import datetime - -from const import ( - BASE_DIR, - TARGET_CLUSTER, - PROBA_THRESHOLD, - FEATURE_COLS -) +from datetime import date, datetime +from pathlib import Path +from typing import Dict, Any + +import pandas as pd +import yaml +from huggingface_hub import HfApi + from src.utils.logger import setup_logger -from src.utils.config_loader import TICKERS, BENCHMARK_TICKER, MARKET_NAME +from src.utils.config_loader import load_market_config from src.utils.market_utils import build_export_df - from src.pipeline.etl import get_data_pipeline, load_models -from src.pipeline.backtest import backtest_strategy_with_rebalancing, get_optimal_weights +from src.backtest.backtest import backtest_strategy_with_rebalancing +from src.strategy.signals import AlphaSignal + +warnings.filterwarnings("ignore") +logger = setup_logger("DailyRun") + # ============================================================================= -# INITIALIZATION +# 1. GLOBAL CONFIG # ============================================================================= -warnings.filterwarnings('ignore') -logger = setup_logger("DailyRun") +BASE_DIR = Path(__file__).resolve().parent +BACKTEST_CONFIG_PATH = BASE_DIR / "config" / "backtest_config.yaml" + + +def load_global_config() -> Dict[str, Any]: + if not BACKTEST_CONFIG_PATH.exists(): + raise FileNotFoundError(f"Missing config file: {BACKTEST_CONFIG_PATH}") + + with open(BACKTEST_CONFIG_PATH, "r", encoding="utf-8") as f: + cfg = yaml.safe_load(f) or {} + + paths_cfg = cfg.get("paths", {}) + strategy_cfg = cfg.get("strategy", {}) + hf_cfg = cfg.get("huggingface", {}) + backtest_cfg = cfg.get("backtest", {}) + + config_dir = Path(paths_cfg.get("config_dir", "config")) + if not config_dir.is_absolute(): + config_dir = BASE_DIR / config_dir + + end_time_raw = backtest_cfg.get("end_time") + end_time = end_time_raw if end_time_raw else date.today().strftime("%Y-%m-%d") + + return { + "BASE_DIR": BASE_DIR, + "CONFIG_DIR": config_dir, + "TARGET_CLUSTER": strategy_cfg.get("target_cluster", 1), + "PROBA_THRESHOLD": strategy_cfg.get("proba_threshold", 0.55), + "TOP_K": strategy_cfg.get("top_k", 5), + "FEATURE_COLS": strategy_cfg.get("feature_cols", []), + "HF_TOKEN": os.getenv("HF_TOKEN"), + "REPO_ID": hf_cfg.get("repo_id", os.getenv("HF_REPO_ID", "")), + "END_TIME": end_time, + } + + +GLOBAL_CFG = load_global_config() + +CONFIG_DIR = GLOBAL_CFG["CONFIG_DIR"] +TARGET_CLUSTER = GLOBAL_CFG["TARGET_CLUSTER"] +PROBA_THRESHOLD = GLOBAL_CFG["PROBA_THRESHOLD"] +TOP_K = GLOBAL_CFG["TOP_K"] +FEATURE_COLS = GLOBAL_CFG["FEATURE_COLS"] +HF_TOKEN = GLOBAL_CFG["HF_TOKEN"] +REPO_ID = GLOBAL_CFG["REPO_ID"] +END_TIME = GLOBAL_CFG["END_TIME"] + +logger.info(f"Pipeline running for period up to: {END_TIME}") + # ============================================================================= -# MAIN ORCHESTRATOR +# 2. HUGGING FACE SYNC # ============================================================================= +def upload_to_hub(df: pd.DataFrame, filename: str) -> None: + if df is None or df.empty: + logger.warning(f"Skip upload for {filename}: empty dataframe") + return + + if not HF_TOKEN or not REPO_ID: + logger.info(f"Local mode: HF upload skipped for {filename}") + return + + try: + api = HfApi() + parquet_buffer = io.BytesIO() + df.to_parquet(parquet_buffer, index=True, compression="gzip") + parquet_buffer.seek(0) + + api.upload_file( + path_or_fileobj=parquet_buffer, + path_in_repo=f"data/{filename}.parquet", + repo_id=REPO_ID, + repo_type="dataset", + token=HF_TOKEN, + ) + logger.info(f"Sync successful on HF: {filename}.parquet") + + except Exception as e: + logger.error(f"Sync failed for {filename}: {e}") + + +# ============================================================================= +# 3. TOP-K ALLOCATION +# ============================================================================= + +def build_topk_allocation(today_data: pd.DataFrame) -> Dict[str, float]: + if today_data.empty: + return {} + + selected = today_data[ + (today_data["cluster"] == TARGET_CLUSTER) & + (today_data["proba_upside"] >= PROBA_THRESHOLD) + ].copy() + + if selected.empty: + logger.warning("No assets passed cluster + probability filters.") + return {} + + selected = selected.sort_values("proba_upside", ascending=False).head(TOP_K) + + n_assets = len(selected) + if n_assets == 0: + return {} -def run_pipeline(): + weight = 1.0 / n_assets + allocation = {ticker: weight for ticker in selected.index.tolist()} + + logger.info( + f"Top-k allocation built with {n_assets} assets | " + f"cluster={TARGET_CLUSTER} | threshold={PROBA_THRESHOLD:.2f} | top_k={TOP_K}" + ) + return allocation + + +# ============================================================================= +# 4. MARKET PIPELINE +# ============================================================================= + +def run_pipeline_for_config(config_file: str) -> None: start_time = datetime.now() + config = load_market_config(config_file) + market_name = config.get("market_name", "Unknown") + logger.info("-" * 60) - logger.info(f"STARTING DAILY PIPELINE | MARKET: {MARKET_NAME}") - logger.info(f"ASSETS: {len(TICKERS)} | BENCHMARK: {BENCHMARK_TICKER}") + logger.info(f"STARTING PIPELINE | MARKET: {market_name}") logger.info("-" * 60) try: - # 1. LOAD MODELS xgb_model, kmeans_model = load_models() - if xgb_model is None: - raise RuntimeError("ML Models not found in src/models/") - - # 2. ETL & FEATURE ENGINEERING - df_daily, df_monthly = get_data_pipeline() - if df_daily is None or df_monthly is None: - raise RuntimeError("Data Pipeline failure.") - - # 3. GENERATE CURRENT SIGNALS - last_date = df_monthly.index.get_level_values('date').max() - logger.info(f"Generating signals for: {last_date.date()}") - - today_data = df_monthly.xs(last_date, level=0).copy() - today_data['cluster'] = kmeans_model.predict(today_data[['rsi']].fillna(50)) - today_data['proba_upside'] = xgb_model.predict_proba( - today_data[FEATURE_COLS].fillna(0))[:, 1] - selected = today_data[ - (today_data['cluster'] == TARGET_CLUSTER) & - (today_data['proba_upside'] > PROBA_THRESHOLD) - ] - final_alloc = {} - if not selected.empty: - tickers = selected.index.tolist() - prices_subset = df_daily['adj close'].unstack()[tickers].iloc[-252:].dropna(axis=1) - weights, success = get_optimal_weights(prices_subset) - final_alloc = weights if success else {t: 1.0/len(tickers) for t in tickers} - - # 4. EXPORT DAILY SIGNALS - export_df = build_export_df(today_data, final_alloc) - export_df.to_csv(BASE_DIR / 'latest_signals.csv', index=False) - logger.info(f"Signals exported: {len(selected)} BUY signals.") + df_daily, df_monthly = get_data_pipeline(config_file) - # 5. BACKTESTING & MONITORING - logger.info("Executing strategy backtest...") - hist_df, rebal_df = backtest_strategy_with_rebalancing( - df_daily, + if df_daily is None or df_monthly is None or df_daily.empty or df_monthly.empty: + raise RuntimeError(f"Data pipeline failure for {market_name}") + + logger.info("Generating signal cache (vectorized)...") + signal_generator = AlphaSignal.from_xgboost_kmeans( df_monthly, xgb_model, kmeans_model, - get_optimal_weights - ) - hist_df.to_csv(BASE_DIR / 'portfolio_history.csv') - rebal_df.to_csv(BASE_DIR / 'rebalance_history.csv') - # 6. METADATA UPDATE + FEATURE_COLS, + ) + + last_date = df_monthly.index.get_level_values("date").max() + today_data = df_monthly.xs(last_date, level="date").copy() + + today_signals = signal_generator.get_signal(last_date) + today_data["proba_upside"] = today_signals["proba_upside"] + today_data["cluster"] = today_signals["cluster"] + + final_alloc = build_topk_allocation(today_data) + + logger.info("Running Top-k backtest...") + hist_df, rebal_df = backtest_strategy_with_rebalancing( + df_daily=df_daily, + signal_generator=signal_generator, + top_k=TOP_K, + target_cluster=TARGET_CLUSTER, + proba_threshold=PROBA_THRESHOLD, + ) + + logger.info("=== DEBUG HIST_DF TAIL ===") + logger.info(f"\n{hist_df.tail(20)}") + + logger.info("=== WORST STRATEGY RETURNS ===") + logger.info(f"\n{hist_df['Strategy'].pct_change().sort_values().head(20)}") + + logger.info("=== FOCUS 2024-09 TO 2025-03 ===") + logger.info(f"\n{hist_df.loc['2024-09-01':'2025-03-31']}") + + logger.info("=== AROUND BREAK DATE ===") + crash_date = hist_df["Strategy"].pct_change().idxmin() + logger.info(f"Crash date detected: {crash_date}") + + start_debug = crash_date - pd.Timedelta(days=10) + end_debug = crash_date + pd.Timedelta(days=10) + logger.info(f"\n{hist_df.loc[start_debug:end_debug]}") + + export_df = build_export_df(today_data, final_alloc) + + suffix = config_file.replace(".json", "") + upload_to_hub(export_df, f"latest_signals_{suffix}") + upload_to_hub(hist_df, f"portfolio_history_backtest_{suffix}") + upload_to_hub(rebal_df, f"rebalance_history_backtest_{suffix}") + metadata = { - 'market_name': MARKET_NAME, - 'last_update': datetime.now().isoformat(), - 'n_assets_tracked': len(TICKERS), - 'current_allocation': final_alloc + "market_name": market_name, + "strategy_method": "topk", + "top_k": TOP_K, + "target_cluster": TARGET_CLUSTER, + "proba_threshold": PROBA_THRESHOLD, + "last_update": datetime.now().isoformat(), + "current_allocation": final_alloc, + "metrics": { + "final_value": float(hist_df["Strategy"].iloc[-1]) if not hist_df.empty else 0.0 + }, } - with open(BASE_DIR / 'data_metadata.json', 'w') as f: - json.dump(metadata, f, indent=4) + + with open(BASE_DIR / f"metadata_{suffix}.json", "w", encoding="utf-8") as f: + json.dump(metadata, f, indent=4, ensure_ascii=False) duration = (datetime.now() - start_time).total_seconds() - logger.info(f"PIPELINE COMPLETED SUCCESSFULLY in {duration:.1f}s") + logger.info(f"SUCCESS: {market_name} processed in {duration:.1f}s") except Exception as e: - logger.critical(f"CRITICAL FAILURE: {e}", exc_info=True) - sys.exit(1) + logger.error(f"FAILURE for {market_name}: {e}", exc_info=True) + + +# ============================================================================= +# 5. GLOBAL EXECUTION +# ============================================================================= + +def run_all_pipelines() -> None: + if not CONFIG_DIR.exists(): + logger.error(f"Config directory not found at {CONFIG_DIR}") + return + + config_files = sorted([f for f in os.listdir(CONFIG_DIR) if f.endswith(".json")]) + + if not config_files: + logger.warning("No JSON config files found.") + return + + logger.info(f"Found {len(config_files)} markets to process.") + for config_file in config_files: + run_pipeline_for_config(config_file) + - if __name__ == "__main__": - run_pipeline() + run_all_pipelines() \ No newline at end of file diff --git a/data/daily_raw_cac40.parquet b/data/daily_raw_cac40.parquet new file mode 100644 index 0000000..5b773cd Binary files /dev/null and b/data/daily_raw_cac40.parquet differ diff --git a/data/daily_raw_market_config.parquet b/data/daily_raw_market_config.parquet new file mode 100644 index 0000000..73ea779 Binary files /dev/null and b/data/daily_raw_market_config.parquet differ diff --git a/data/daily_raw_nasdaq.parquet b/data/daily_raw_nasdaq.parquet new file mode 100644 index 0000000..5c49083 Binary files /dev/null and b/data/daily_raw_nasdaq.parquet differ diff --git a/data/daily_raw_sp500.parquet b/data/daily_raw_sp500.parquet new file mode 100644 index 0000000..90d3ad2 Binary files /dev/null and b/data/daily_raw_sp500.parquet differ diff --git a/data/monthly_features_cac40.parquet b/data/monthly_features_cac40.parquet new file mode 100644 index 0000000..36d3c5d Binary files /dev/null and b/data/monthly_features_cac40.parquet differ diff --git a/data/monthly_features_market_config.parquet b/data/monthly_features_market_config.parquet new file mode 100644 index 0000000..acf78bb Binary files /dev/null and b/data/monthly_features_market_config.parquet differ diff --git a/data/monthly_features_nasdaq.parquet b/data/monthly_features_nasdaq.parquet new file mode 100644 index 0000000..8323f9a Binary files /dev/null and b/data/monthly_features_nasdaq.parquet differ diff --git a/data/monthly_features_sp500.parquet b/data/monthly_features_sp500.parquet new file mode 100644 index 0000000..5a4eb3e Binary files /dev/null and b/data/monthly_features_sp500.parquet differ diff --git a/data_metadata.json b/data_metadata.json index bf32498..549a7d9 100644 --- a/data_metadata.json +++ b/data_metadata.json @@ -1,16 +1,21 @@ { - "market_name": "CAC 40 (France)", - "last_update": "2026-04-08T23:40:25.330056", - "data_start": "2016-04-08T00:00:00", - "n_assets_tracked": 40, - "current_allocation": { - "AI.PA": 0.02, - "CS.PA": 0.02, - "EN.PA": 0.08203, - "ENGI.PA": 0.25, - "ORA.PA": 0.24118, - "STMPA.PA": 0.11679, - "TTE.PA": 0.25, - "VIE.PA": 0.02 - } + "market_name": "NASDAQ 100 (USA)", + "last_update": "2026-05-05T13:37:59.088659", + "n_assets_tracked": 40, + "current_allocation": { + "ADI": 0.02, + "AMD": 0.02, + "AMZN": 0.02, + "AVGO": 0.02, + "CDNS": 0.02, + "CSCO": 0.13031, + "GOOG": 0.15013, + "GOOGL": 0.14512, + "INTC": 0.14444, + "MU": 0.25, + "QCOM": 0.02, + "SBUX": 0.02, + "SNPS": 0.02, + "TXN": 0.02 + } } \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..e69de29 diff --git a/latest_signals.csv b/latest_signals.csv deleted file mode 100644 index 2bd98b1..0000000 --- a/latest_signals.csv +++ /dev/null @@ -1,39 +0,0 @@ -Ticker,Cluster,Proba_Hausse,RSI,Return_3M,Allocation,Signal -AI.PA,3,62.235756,68.58512972623429,0.16145371410552034,0.02,BUY -AIR.PA,1,42.32057,50.30322769694975,-0.09379524282383234,0.0,NEUTRAL -ALO.PA,1,49.613293,50.100740438153075,-0.06994823334483014,0.0,NEUTRAL -ATO.PA,0,49.986675,39.6927509788373,-0.38547687711906564,0.0,NEUTRAL -BNP.PA,2,41.844994,56.03065701776109,-0.013377123159345805,0.0,NEUTRAL -CA.PA,2,61.213474,61.48737854957211,0.17015892458613702,0.0,NEUTRAL -CAP.PA,1,39.860806,45.168050934049404,-0.21341463911044045,0.0,NEUTRAL -CS.PA,3,62.819893,63.43346641415173,0.07364033291397809,0.02,BUY -DG.PA,2,48.860962,59.8217351961611,0.12546433665863255,0.0,NEUTRAL -DSY.PA,1,32.690876,43.66712337169983,-0.2403100813399609,0.0,NEUTRAL -EL.PA,0,33.519524,38.85531496491026,-0.22179138542826438,0.0,NEUTRAL -EN.PA,3,63.54872,62.415774003696356,0.14974781681558014,0.08203,BUY -ENGI.PA,3,63.10771,62.55136465130157,0.15139438961387142,0.25,BUY -ERF.PA,2,50.123535,53.35228582791283,-0.04167884301921587,0.0,NEUTRAL -FR.PA,1,51.89677,51.381014389414545,-0.052030438832199155,0.0,NEUTRAL -GLE.PA,2,41.8001,55.52480154563481,-0.04322496354328087,0.0,NEUTRAL -HO.PA,2,58.140522,60.503458732927065,0.05585932731628418,0.0,NEUTRAL -KER.PA,2,48.479946,57.29730260428383,0.049593058512995114,0.0,NEUTRAL -LR.PA,2,47.001667,58.718037337856614,0.09111113371672452,0.0,NEUTRAL -MC.PA,1,44.10933,50.08669714596178,-0.08785887029722972,0.0,NEUTRAL -ML.PA,1,45.346798,50.98178173828877,-0.02583730322444122,0.0,NEUTRAL -OR.PA,2,37.48979,51.577324797366785,-0.052196413971656974,0.0,NEUTRAL -ORA.PA,3,63.969135,62.97194021624521,0.15012805916834826,0.24118,BUY -PUB.PA,2,45.548046,52.424177686299714,-0.10926362567325787,0.0,NEUTRAL -RI.PA,0,36.487595,40.501405263007335,-0.14038359960678337,0.0,NEUTRAL -RMS.PA,1,33.62552,44.36314541597167,-0.12660078699336463,0.0,NEUTRAL -RNO.PA,2,53.050377,58.210656021649214,-0.013174406755029677,0.0,NEUTRAL -SAF.PA,2,41.089447,54.038996697880016,0.040199355825633276,0.0,NEUTRAL -SAN.PA,2,58.893044,53.505206531976,0.0210859326097097,0.0,NEUTRAL -SGO.PA,1,43.9304,50.846325396105236,-0.08363372966090721,0.0,NEUTRAL -STLAP.PA,2,49.610046,54.14998174600833,-0.18884996217870453,0.0,NEUTRAL -STMPA.PA,3,64.576744,64.64905347327654,0.35485481458857127,0.11679,BUY -SU.PA,2,41.380188,54.835090438882396,0.05633509585044694,0.0,NEUTRAL -TEP.PA,1,45.786144,47.699796857742804,-0.07875456698224326,0.0,NEUTRAL -TTE.PA,3,60.77994,61.550697006474834,0.26940920808501856,0.25,BUY -VIE.PA,3,61.681713,61.903364411865326,0.09326597371356327,0.02,BUY -VIV.PA,2,50.98823,56.24876003547372,-0.11639768784628424,0.0,NEUTRAL -WLN.PA,0,52.974094,27.336102605386003,-0.8136602445915727,0.0,NEUTRAL diff --git a/metadata_cac40.json b/metadata_cac40.json new file mode 100644 index 0000000..f2835ad --- /dev/null +++ b/metadata_cac40.json @@ -0,0 +1,18 @@ +{ + "market_name": "CAC 40 (France)", + "strategy_method": "topk", + "top_k": 5, + "target_cluster": 3, + "proba_threshold": 0.55, + "last_update": "2026-05-06T18:10:33.192045", + "current_allocation": { + "CA.PA": 0.2, + "EN.PA": 0.2, + "TEP.PA": 0.2, + "PUB.PA": 0.2, + "STMPA.PA": 0.2 + }, + "metrics": { + "final_value": 116.45620521666254 + } +} \ No newline at end of file diff --git a/metadata_market_config.json b/metadata_market_config.json new file mode 100644 index 0000000..5a08e10 --- /dev/null +++ b/metadata_market_config.json @@ -0,0 +1,17 @@ +{ + "market_name": "CAC 40 (France)", + "last_update": "2026-05-06T16:32:29.435958", + "current_allocation": { + "AIR.PA": 0.02, + "CA.PA": 0.25, + "EN.PA": 0.25, + "LR.PA": 0.17, + "PUB.PA": 0.02, + "STMPA.PA": 0.25, + "TEP.PA": 0.02, + "VIE.PA": 0.02 + }, + "metrics": { + "final_value": 309.6180406362211 + } +} \ No newline at end of file diff --git a/metadata_nasdaq.json b/metadata_nasdaq.json new file mode 100644 index 0000000..4b9544f --- /dev/null +++ b/metadata_nasdaq.json @@ -0,0 +1,18 @@ +{ + "market_name": "NASDAQ 100 (USA)", + "strategy_method": "topk", + "top_k": 5, + "target_cluster": 3, + "proba_threshold": 0.55, + "last_update": "2026-05-06T18:10:43.763721", + "current_allocation": { + "MDLZ": 0.2, + "CSX": 0.2, + "SBUX": 0.2, + "AAPL": 0.2, + "CDNS": 0.2 + }, + "metrics": { + "final_value": 720.8034690633889 + } +} \ No newline at end of file diff --git a/metadata_sp500.json b/metadata_sp500.json new file mode 100644 index 0000000..6bbcc91 --- /dev/null +++ b/metadata_sp500.json @@ -0,0 +1,18 @@ +{ + "market_name": "S&P 500 (USA)", + "strategy_method": "topk", + "top_k": 5, + "target_cluster": 3, + "proba_threshold": 0.55, + "last_update": "2026-05-06T18:10:53.449777", + "current_allocation": { + "ORCL": 0.2, + "UNH": 0.2, + "AAPL": 0.2, + "GOOGL": 0.2, + "AVGO": 0.2 + }, + "metrics": { + "final_value": 511.6113551257301 + } +} \ No newline at end of file diff --git a/portfolio_history.csv b/portfolio_history.csv deleted file mode 100644 index 6ad4c3e..0000000 --- a/portfolio_history.csv +++ /dev/null @@ -1,2525 +0,0 @@ -Date,Strategy,Benchmark -2016-05-31,99.84725821503275,99.47499038130978 -2016-06-01,98.76000338093854,98.8075734801634 -2016-06-02,99.01635751224232,98.60025823043482 -2016-06-03,97.88385403143782,97.62396521597019 -2016-06-06,97.60865180974108,97.65929213986186 -2016-06-07,98.20124731420755,98.81794409376846 -2016-06-08,97.4425250846527,98.21897108636274 -2016-06-09,96.1569136306517,97.2669660058401 -2016-06-10,93.42023188916465,95.08368233538457 -2016-06-13,91.3477570594357,93.32406302530202 -2016-06-14,89.19851918645581,91.18934444246686 -2016-06-15,89.96100701555439,92.10006111331447 -2016-06-16,89.50690783073034,91.69006612721508 -2016-06-17,91.28018706465593,92.5912961660747 -2016-06-20,93.97742053207787,95.83520685331541 -2016-06-21,95.00998802575835,96.41984211010292 -2016-06-22,95.149288503797,96.70220955517289 -2016-06-23,98.25693582331799,98.59804827639215 -2016-06-24,88.11726107291112,90.6683019607898 -2016-06-27,84.38736826756251,88.98088346632046 -2016-06-28,86.82656428901743,90.27355026745295 -2016-06-29,89.65005958164959,92.62418675038762 -2016-06-30,89.65005958164959,93.554997832628 -2016-07-01,89.65005958164959,94.36040210814524 -2016-07-04,89.65005958164959,93.49715093802847 -2016-07-05,89.65005958164959,91.91990134765153 -2016-07-06,89.65005958164959,90.19517236078394 -2016-07-07,89.65005958164959,90.9138116845337 -2016-07-08,89.65005958164959,92.52175268544451 -2016-07-11,89.65005958164959,94.15220287679958 -2016-07-12,89.65005958164959,95.62811798912291 -2016-07-13,89.65005958164959,95.71377796386906 -2016-07-14,89.65005958164959,96.82342283934678 -2016-07-15,89.65005958164959,96.53618271511932 -2016-07-18,89.65005958164959,96.21010130105921 -2016-07-19,89.65005958164959,95.60052051424873 -2016-07-20,89.65005958164959,96.6962480693895 -2016-07-21,89.65005958164959,96.61875953446936 -2016-07-22,89.65005958164959,96.72583989303386 -2016-07-25,89.65005958164959,96.87817579828655 -2016-07-26,89.65005958164959,97.02764415341561 -2016-07-27,89.65005958164959,98.17989263073032 -2016-07-28,89.65005958164959,97.5974781082491 -2016-07-29,92.57678484293375,98.02203723050279 -2016-08-01,92.79701042683176,97.34556490791331 -2016-08-02,90.09097800201737,95.55328139905393 -2016-08-03,90.24556760883982,95.40071910826515 -2016-08-04,91.80471105355015,95.9427292026884 -2016-08-05,93.5462922433568,97.37602993291111 -2016-08-08,93.59466873883869,97.48443626390122 -2016-08-09,94.08678489997561,98.64595576793147 -2016-08-10,93.17726061626989,98.2913821171165 -2016-08-11,93.86866314454821,99.43812187972001 -2016-08-12,93.86886795864237,99.35510306956142 -2016-08-15,94.35834730541565,99.30365965155379 -2016-08-16,94.08310779744617,98.47750336856281 -2016-08-17,92.77103560488192,97.53345412259374 -2016-08-18,94.71077033289583,97.96132278577959 -2016-08-19,94.16225053746479,97.15459253783676 -2016-08-22,93.46447684664844,96.92100578565962 -2016-08-23,94.68019393748546,97.61668853802477 -2016-08-24,93.74861212300131,97.92622224742402 -2016-08-25,93.07504356325343,97.28904398573937 -2016-08-26,93.89899762183155,98.06751916272704 -2016-08-29,92.7984927971064,97.67850256963747 -2016-08-30,92.85083864832416,98.41237979601794 -2016-08-31,93.03135795617514,97.9869366921472 -2016-09-01,93.19342113968993,98.01894329484306 -2016-09-02,94.62862450347086,100.281936234525 -2016-09-05,94.27180737493039,100.2578746861191 -2016-09-06,94.41653708641934,100.01236496237522 -2016-09-07,94.79111008002826,100.62392931769227 -2016-09-08,94.15642855922745,100.28260461086963 -2016-09-09,93.49866208444735,99.16103676382518 -2016-09-12,92.3314291405232,98.02181084496672 -2016-09-13,91.27495540494937,96.86007573566401 -2016-09-14,91.55669752381205,96.4865072603458 -2016-09-15,91.63680948150734,96.55186799869037 -2016-09-16,92.28140498696234,95.65174832698389 -2016-09-19,92.63089980622718,97.01483720023181 -2016-09-20,93.18293594459847,96.89142474227887 -2016-09-21,93.68741807559056,97.35395195301179 -2016-09-22,95.23371882195556,99.56771142872874 -2016-09-23,95.07958990574797,99.10120630071904 -2016-09-26,93.66982223023786,97.31642585534107 -2016-09-27,92.79629011349117,97.11397250450634 -2016-09-28,93.4818041483339,97.85954631691746 -2016-09-29,93.63691621966326,98.11100674618108 -2016-09-30,95.33582162178051,98.20858969249396 -2016-10-03,95.63019443611556,98.3256094541186 -2016-10-04,96.09383200743035,99.41912705521672 -2016-10-05,96.04428573249281,99.12903016112925 -2016-10-06,96.46653534347136,98.91155990306807 -2016-10-07,96.66892164578358,98.24502698353875 -2016-10-10,97.54869458232868,99.29041070756142 -2016-10-11,96.2899448546841,98.72699100958344 -2016-10-12,94.75680480622242,98.29647040154639 -2016-10-13,95.06570992691556,97.25725298831591 -2016-10-14,96.27370428349373,98.70888016669726 -2016-10-17,97.11785938917828,98.25208805621163 -2016-10-18,97.73799551901462,99.54762779759956 -2016-10-19,98.15762420288964,99.79908822686319 -2016-10-20,97.24143929293066,100.23668068783675 -2016-10-21,98.5841370829336,100.14725840108628 -2016-10-24,99.24573151941817,100.51177145496139 -2016-10-25,96.64742084651013,100.25257079641665 -2016-10-26,96.49623789666381,100.1145834220458 -2016-10-27,99.64177751181825,100.09206345133792 -2016-10-28,101.40633822820713,100.42345953536405 -2016-10-31,101.5209088550121,99.55534646635344 -2016-11-01,99.724408552022,98.69474724108787 -2016-11-02,98.0640705152183,97.4669937973596 -2016-11-03,99.54448099731955,97.40098624319768 -2016-11-04,98.28839477075894,96.64547302772641 -2016-11-07,101.31892764544989,98.4945038442958 -2016-11-08,100.7693553209114,98.84069045001229 -2016-11-09,105.13501284870439,100.31085968182472 -2016-11-10,105.11700745905296,100.03422733700204 -2016-11-11,104.11041592671522,99.11401325390281 -2016-11-14,106.39254575607313,99.539671963046 -2016-11-15,106.76964204816922,100.15741340941888 -2016-11-16,106.274696304644,99.37608146257118 -2016-11-17,107.02284121754258,99.96401548002723 -2016-11-18,107.15223045185583,99.44695091562696 -2016-11-21,107.90755484342165,100.00397791727666 -2016-11-22,110.52023252820153,100.41838203119774 -2016-11-23,110.46982529444846,99.99580647745063 -2016-11-24,110.88472553407995,100.2905496651595 -2016-11-25,110.56285939848232,100.4607700277623 -2016-11-28,109.33524261955178,99.58030277664005 -2016-11-29,110.60281041079942,100.48704153021089 -2016-11-30,111.88175360871388,101.08049504264177 -2016-12-01,112.34272412151503,100.6890528902371 -2016-12-02,110.7922118456751,99.9871930468161 -2016-12-05,113.25595098066972,100.99174113223589 -2016-12-06,115.2245913068296,102.26387692129889 -2016-12-07,118.4027797136065,103.64993853632683 -2016-12-08,121.75030622963655,104.54983182249723 -2016-12-09,119.68648429979,105.1810378181349 -2016-12-12,119.47809967950847,105.10818479657254 -2016-12-13,118.9859206786475,106.05974788628666 -2016-12-14,119.01423093034037,105.29519002963592 -2016-12-15,120.34912482063832,106.39886263906665 -2016-12-16,120.35103023071953,106.70883833927442 -2016-12-19,119.0109173304924,106.47701955033139 -2016-12-20,120.10437442288503,107.07577695246465 -2016-12-21,120.41932499999572,106.7209769161136 -2016-12-22,119.6040137515466,106.7388613734637 -2016-12-23,119.81749930067453,106.85036164011352 -2016-12-27,119.7449800856579,107.04022364303692 -2016-12-28,119.99444944674501,107.03426215725356 -2016-12-29,119.02755483022914,106.82364814685644 -2016-12-30,119.51731252136761,107.34998373797227 -2017-01-02,120.04666340003011,107.79308491365704 -2017-01-03,120.55639164126336,108.16731098505625 -2017-01-04,120.21849210516358,108.1688525627543 -2017-01-05,119.89020003605107,108.19623443235602 -2017-01-06,119.84121434935243,108.39934537927175 -2017-01-09,119.3258002374928,107.907668335703 -2017-01-10,119.46438058219447,107.92224325212092 -2017-01-11,120.09768137195559,107.93284025126205 -2017-01-12,119.99296063460196,107.38663663428956 -2017-01-13,121.76825919119176,108.67864044920924 -2017-01-16,120.45899193633049,107.78867578583537 -2017-01-17,120.01950619182331,107.29213684337276 -2017-01-18,120.11437486934084,107.15326548738484 -2017-01-19,119.72599526422272,106.88259462834552 -2017-01-20,120.24377771082433,107.0929930334702 -2017-01-23,119.08171652654961,106.44699651614215 -2017-01-24,119.67870881329137,106.63730050987408 -2017-01-25,121.01697216015958,107.68909849075226 -2017-01-26,121.35507695231426,107.4588320597709 -2017-01-27,120.89733441660184,106.8569807219779 -2017-01-30,119.72392219196585,105.635188764033 -2017-01-31,119.72392219196585,104.8461165879042 -2017-02-01,119.72392219196585,105.85464259060078 -2017-02-02,119.72392219196585,105.84823911400888 -2017-02-03,119.72392219196585,106.53552404101195 -2017-02-06,119.72392219196585,105.49035592226176 -2017-02-07,119.72392219196585,104.96909783531224 -2017-02-08,119.72392219196585,105.23690114422791 -2017-02-09,119.72392219196585,106.55363488389814 -2017-02-10,119.72392219196585,106.59954802666732 -2017-02-13,119.72392219196585,107.92135927050384 -2017-02-14,119.72392219196585,108.08981166987249 -2017-02-15,119.72392219196585,108.7309570685703 -2017-02-16,119.72392219196585,108.17017853517989 -2017-02-17,119.72392219196585,107.46633512325232 -2017-02-20,119.72392219196585,107.4091566049974 -2017-02-21,119.72392219196585,107.93393983815155 -2017-02-22,119.72392219196585,108.09113764229808 -2017-02-23,119.72392219196585,107.98980316424449 -2017-02-24,119.72392219196585,106.97311650198552 -2017-02-27,119.72392219196585,106.97179052955993 -2017-02-28,120.97375739993119,107.26763330415831 -2017-03-01,122.86524364491736,109.52510674886543 -2017-03-02,123.04292989594428,109.59067231221883 -2017-03-03,123.17033121092827,110.28237714730722 -2017-03-06,122.30161987128622,109.77590958204809 -2017-03-07,121.9213098069522,109.39639040121013 -2017-03-08,122.76538669013405,109.51737729984794 -2017-03-09,121.79115050088107,109.981672473815 -2017-03-10,121.51454505773809,110.24241471005779 -2017-03-13,121.72141743920575,110.38107046077326 -2017-03-14,121.88833280524501,109.82160711954482 -2017-03-15,122.31419846157995,110.06932679733136 -2017-03-16,122.636173296784,110.68530028047012 -2017-03-17,122.7167864506226,111.0354648034634 -2017-03-20,122.7724066692241,110.65837118194055 -2017-03-21,120.71068861224809,110.44355286873056 -2017-03-22,121.22220349899536,110.27289051531925 -2017-03-23,122.35173095141556,111.113168943656 -2017-03-24,123.78602167684345,110.85132712052369 -2017-03-27,122.38231001085771,110.77472256722062 -2017-03-28,123.44114257001978,111.40990648013508 -2017-03-29,123.64421382673257,111.91416409135155 -2017-03-30,123.87661940502873,112.3689726333306 -2017-03-31,124.99008694787082,113.09466763962142 -2017-04-03,124.58397497469421,112.28662219951661 -2017-04-04,124.55929383140816,112.62264301663689 -2017-04-05,124.93239563586684,112.41776410648704 -2017-04-06,125.76691597349011,113.07104808202403 -2017-04-07,126.242768373376,113.3766038741465 -2017-04-10,125.4977971972536,112.76218274896942 -2017-04-11,125.16521718086071,112.63875951075286 -2017-04-12,124.95651646569333,112.62220102582836 -2017-04-13,124.62582987357003,111.95964602357581 -2017-04-18,122.54288100643583,110.17463919266177 -2017-04-19,122.78841675461688,110.47224993049429 -2017-04-20,124.18970970043796,112.10999836032194 -2017-04-21,123.81397781909263,111.69692021882645 -2017-04-24,128.90409171816768,116.32556654866954 -2017-04-25,128.7727909059532,116.52492596384454 -2017-04-26,129.43893803614182,116.7457057628379 -2017-04-27,129.39427121191665,116.38849094743536 -2017-04-28,129.7027149782977,116.29200758801198 -2017-05-02,130.85070643368365,117.10491492701063 -2017-05-03,131.33011647755757,117.03537144638044 -2017-05-04,132.8201196081233,118.61217904594885 -2017-05-05,134.1925334295301,119.93641584910048 -2017-05-08,132.53181841355078,118.84466621123649 -2017-05-09,132.07851347696607,119.1771511018885 -2017-05-10,132.20050294760136,119.23124646474733 -2017-05-11,131.97153935005028,118.85503682484155 -2017-05-12,132.30813938452377,119.34075238262693 -2017-05-15,132.76764853824815,119.60524615061043 -2017-05-16,132.8329447326931,119.35576928985338 -2017-05-17,130.2973678319467,117.40827154535404 -2017-05-18,130.4511418092262,116.78655218170438 -2017-05-19,131.7259100514233,117.55199401997218 -2017-05-22,131.2100105470374,117.51843505931464 -2017-05-23,131.9242757875597,118.07657242811749 -2017-05-24,132.30387216917833,117.9259937058353 -2017-05-25,132.40824901227077,117.83371464922479 -2017-05-26,132.11857339346318,117.8222336684666 -2017-05-29,132.15995528597827,117.73017021712855 -2017-05-30,131.75064416733287,117.14443537345153 -2017-05-31,132.284241418505,116.65187434826571 -2017-06-01,132.62902058002754,117.42548762635953 -2017-06-02,132.94238005086638,117.97170202359565 -2017-06-05,132.54117792739672,117.18749174636069 -2017-06-06,132.54455751844864,116.33373798849556 -2017-06-07,132.63361434835804,116.25226075603503 -2017-06-08,132.6164879749684,116.22379007980742 -2017-06-09,132.82247609093758,117.00688998988923 -2017-06-12,131.57890446522472,115.70163723097721 -2017-06-13,131.52037574163765,116.16859513005906 -2017-06-14,132.2665069415967,115.76125208881086 -2017-06-15,131.71759581413767,115.17816918998504 -2017-06-16,133.25815632599793,116.20325367760613 -2017-06-19,133.5459889641156,117.24997415431802 -2017-06-20,133.3201419583745,116.87309613806764 -2017-06-21,133.3152597878011,116.4450010893457 -2017-06-22,133.18507482026504,116.61434825059504 -2017-06-23,133.31099241287035,116.2652940947549 -2017-06-26,133.91244021347066,116.91946205190897 -2017-06-27,132.3545594502586,116.09882526389282 -2017-06-28,131.68846033319494,115.97341845716969 -2017-06-29,129.3962107700167,113.79763785019556 -2017-06-30,129.3962107700167,113.05427399182709 -2017-07-03,129.3962107700167,114.71100646589434 -2017-07-04,129.3962107700167,114.25133602502144 -2017-07-05,129.3962107700167,114.36614583260344 -2017-07-06,129.3962107700167,113.75458147728638 -2017-07-07,129.3962107700167,113.59474250855227 -2017-07-10,129.3962107700167,114.04689910568013 -2017-07-11,129.3962107700167,113.49406562657967 -2017-07-12,129.3962107700167,115.29407858445656 -2017-07-13,129.3962107700167,115.58705380893129 -2017-07-14,129.3962107700167,115.5850702404247 -2017-07-17,129.3962107700167,115.4715864052683 -2017-07-18,129.3962107700167,114.2153515050488 -2017-07-19,129.3962107700167,115.16028473263495 -2017-07-20,129.3962107700167,114.78827939554203 -2017-07-21,129.3962107700167,112.98759806132055 -2017-07-24,129.3962107700167,113.20926184193098 -2017-07-25,129.3962107700167,113.94622222370757 -2017-07-26,129.3962107700167,114.5884672092949 -2017-07-27,129.3962107700167,114.51738215096667 -2017-07-28,129.3962107700167,113.29072829412793 -2017-07-31,129.3962107700167,112.46015210305164 -2017-08-01,129.3962107700167,113.19446053997702 -2017-08-02,129.3962107700167,112.75776284088414 -2017-08-03,129.3962107700167,113.27086026827125 -2017-08-04,129.3962107700167,114.88144243376965 -2017-08-07,129.3962107700167,114.97969375642715 -2017-08-08,129.3962107700167,115.22255153531985 -2017-08-09,129.3962107700167,113.60666548011908 -2017-08-10,129.3962107700167,112.93394468927032 -2017-08-11,129.3962107700167,111.73488830730574 -2017-08-14,129.3962107700167,113.07612558619041 -2017-08-15,129.3962107700167,113.48633617756225 -2017-08-16,129.3962107700167,114.28908850822829 -2017-08-17,129.3962107700167,113.63205300095058 -2017-08-18,129.3962107700167,112.91009874613684 -2017-08-21,129.3962107700167,112.32370630637884 -2017-08-22,129.3962107700167,113.30109890773299 -2017-08-23,129.3962107700167,112.93748061573855 -2017-08-24,129.3962107700167,112.88757877542896 -2017-08-25,129.3962107700167,112.69329686442026 -2017-08-28,129.3962107700167,112.15061839365241 -2017-08-29,129.3962107700167,111.09462689022499 -2017-08-30,129.3962107700167,111.6337694345246 -2017-08-31,129.3962107700167,112.27955034658017 -2017-09-01,129.3962107700167,113.11122612454596 -2017-09-04,129.3962107700167,112.6853518101303 -2017-09-05,129.3962107700167,112.3009707303985 -2017-09-06,129.3962107700167,112.62883088795637 -2017-09-07,129.3962107700167,112.92048014000551 -2017-09-08,129.3962107700167,112.89553460998253 -2017-09-11,129.3962107700167,114.29129846227093 -2017-09-12,129.3962107700167,115.00441290091403 -2017-09-13,129.3962107700167,115.19384369329251 -2017-09-14,129.3962107700167,115.36186488211627 -2017-09-15,129.3962107700167,115.11260362663167 -2017-09-18,129.3962107700167,115.45281796630118 -2017-09-19,129.3962107700167,115.63209375034705 -2017-09-20,129.3962107700167,115.72526756883825 -2017-09-21,129.3962107700167,116.29112360639496 -2017-09-22,129.3962107700167,116.60021532498568 -2017-09-25,129.3962107700167,116.28758767992673 -2017-09-26,129.3962107700167,116.32357219989937 -2017-09-27,129.3962107700167,116.61500584667606 -2017-09-28,129.3962107700167,116.87574808291885 -2017-09-29,130.01880060569113,117.671439340912 -2017-10-02,130.77228705954556,118.12690547897203 -2017-10-03,131.33680713407952,118.50157354117977 -2017-10-04,131.158009142144,118.40928370430564 -2017-10-05,130.9830545296849,118.76208939188649 -2017-10-06,130.5208617303445,118.33576230639868 -2017-10-09,130.68897180385719,118.46668860809665 -2017-10-10,130.70574875988567,118.41855473102119 -2017-10-11,130.9461812659147,118.3911836416831 -2017-10-12,130.92443809553683,118.35585671779144 -2017-10-13,131.11963822684515,118.15561332099936 -2017-10-16,131.316270580855,118.40155425528815 -2017-10-17,131.54340030983423,118.36822168016668 -2017-10-18,131.53023448943327,118.86365025547616 -2017-10-19,130.95325660629797,118.52099957622792 -2017-10-20,131.35144161559472,118.61129506433186 -2017-10-23,131.9153609467162,118.92988419517417 -2017-10-24,132.29979968288853,119.10628164883279 -2017-10-25,132.53776854488808,118.66671639961628 -2017-10-26,135.73868991194172,120.44420938678529 -2017-10-27,136.55332338962523,121.29928911707604 -2017-10-30,137.44769692116793,121.28825012712637 -2017-10-31,137.83319932967848,121.50152686263833 -2017-11-01,138.75118230756541,121.74438464153104 -2017-11-02,138.57319468519802,121.66070823529147 -2017-11-03,139.62166240395882,121.8256354884555 -2017-11-06,139.82381045790387,121.58895480061862 -2017-11-07,139.16081900761054,121.0014627739711 -2017-11-08,139.43416413596162,120.7981254415193 -2017-11-09,136.88492302612067,119.39219580063467 -2017-11-10,136.4164487899287,118.7954327472716 -2017-11-13,135.39257055290287,117.9323971824273 -2017-11-14,135.27572567443883,117.35727011815504 -2017-11-15,134.87267721643877,117.04089094135537 -2017-11-16,136.95246131541523,117.81671417349186 -2017-11-17,136.37645227970535,117.4365266163093 -2017-11-20,137.45801319070225,117.9063520655148 -2017-11-21,137.9840608803018,118.47374968076957 -2017-11-22,137.50143664046345,118.17812251144365 -2017-11-23,138.25134926857655,118.7693768500955 -2017-11-24,138.2524973299259,119.01046666575408 -2017-11-27,137.470250923045,118.33995582894798 -2017-11-28,137.92631209487246,119.01090865656262 -2017-11-29,136.84368726388163,119.17803508350569 -2017-11-30,137.1695270462879,118.620350485775 -2017-12-01,135.4517204624012,117.38619356545485 -2017-12-04,137.39959048655712,118.98463715411405 -2017-12-05,138.22197082039804,118.6808385449621 -2017-12-06,138.9545914936886,118.6547934280496 -2017-12-07,139.73256827855985,118.86474984236577 -2017-12-08,139.7362601033154,119.2009970450221 -2017-12-11,138.90024347968034,118.93032618598278 -2017-12-12,140.25127060333702,119.82139043624618 -2017-12-13,138.9905450113023,119.20895287957568 -2017-12-14,137.99223974513103,118.27483225640313 -2017-12-15,137.70540126850256,118.10173356341308 -2017-12-18,138.86811909874538,119.67545800758539 -2017-12-19,138.56846026088803,118.84378222961958 -2017-12-20,137.8599249999275,118.17834889697977 -2017-12-21,138.69887625456565,118.91134214174318 -2017-12-22,138.08657808555165,118.4421850688823 -2017-12-27,137.92232622391305,118.5331381530672 -2017-12-28,136.7413251702872,117.88360570927091 -2017-12-29,136.7413251702872,117.29059418764857 -2018-01-02,136.7413251702872,116.76160665168156 -2018-01-03,136.7413251702872,117.7038879344165 -2018-01-04,136.7413251702872,119.52333770760515 -2018-01-05,136.7413251702872,120.78310853429291 -2018-01-08,136.7413251702872,121.15114673437266 -2018-01-09,136.7413251702872,121.95743499150697 -2018-01-10,136.7413251702872,121.5322182731723 -2018-01-11,136.7413251702872,121.17609226439565 -2018-01-12,136.7413251702872,121.8055410770628 -2018-01-15,136.7413251702872,121.64282377794143 -2018-01-16,136.7413251702872,121.73400324766241 -2018-01-17,136.7413251702872,121.29620596168002 -2018-01-18,136.7413251702872,121.31474801511109 -2018-01-19,136.7413251702872,122.01417151895335 -2018-01-22,136.7413251702872,122.35594899684814 -2018-01-23,136.7413251702872,122.20735384307253 -2018-01-24,136.7413251702872,121.32203547332004 -2018-01-25,136.7413251702872,121.01404334161886 -2018-01-26,136.7413251702872,122.07246040436138 -2018-01-29,136.7413251702872,121.90554958269075 -2018-01-30,136.7413251702872,120.85000007007186 -2018-01-31,137.47891533726664,121.02994423046235 -2018-02-01,136.4825773095105,120.42544094781817 -2018-02-02,134.17778053358032,118.44792016912955 -2018-02-05,132.3083002541327,116.70045021614982 -2018-02-06,129.4910302230154,113.96233871782361 -2018-02-07,131.07408778434788,116.03965239686778 -2018-02-08,129.89559126775126,113.7386913687066 -2018-02-09,128.43594493817707,112.13869542208572 -2018-02-12,129.64437386379606,113.48214265501305 -2018-02-13,129.31898038951087,112.80170319541041 -2018-02-14,130.98785186845498,114.03850128031814 -2018-02-15,133.1692285993326,115.30269201509121 -2018-02-16,134.720754634535,116.60661880157764 -2018-02-19,134.33213867762524,116.04584026818722 -2018-02-20,134.23589070699015,116.78941973182813 -2018-02-21,134.46522550402418,117.06120095802059 -2018-02-22,134.37605158533987,117.21707278974152 -2018-02-23,134.90706765693793,117.39679056459593 -2018-02-26,135.04551268884896,117.99045968229926 -2018-02-27,135.00323429689192,117.98318300435392 -2018-02-28,135.55883998024004,117.46567644914512 -2018-03-01,132.5363611778285,116.18669519268167 -2018-03-02,129.1888159433161,113.40531171617386 -2018-03-05,130.6372576562137,114.08199964403578 -2018-03-06,130.28901467187657,114.1482335837338 -2018-03-07,128.91993683314502,114.53680818601484 -2018-03-08,129.90058892006292,115.9999163451544 -2018-03-09,130.7456713324301,116.44809502500549 -2018-03-12,129.40535829364666,116.49909645220458 -2018-03-13,128.62996010192987,115.75021309886128 -2018-03-14,129.063987550017,115.54201386751564 -2018-03-15,130.14237530217662,116.29045523005041 -2018-03-16,129.936227345984,116.63244831321767 -2018-03-19,130.08457965495958,115.30975308776408 -2018-03-20,129.06417589806577,115.96304784356471 -2018-03-21,128.21239701107757,115.68287957227376 -2018-03-22,126.44094018158127,114.08155765322729 -2018-03-23,125.59409813513422,112.49216948601118 -2018-03-26,125.01479624447676,111.8532232610924 -2018-03-27,127.12136103024794,112.94521006475608 -2018-03-28,127.06607196959426,113.26974990111815 -2018-03-29,127.15866430845213,114.08354122173387 -2018-04-03,126.99354026335413,113.74840438623066 -2018-04-04,126.20803399709841,113.5205527343008 -2018-04-05,127.06038586750012,116.49821247058752 -2018-04-06,127.5945343548571,116.09132220041147 -2018-04-09,127.95650614121277,116.20502164084031 -2018-04-10,128.31175240001414,117.1802042881518 -2018-04-11,128.1466292457769,116.5262519362702 -2018-04-12,128.39101744955678,117.21685718446906 -2018-04-13,128.72652467525913,117.34490515577977 -2018-04-16,128.72819105336671,117.29942322355551 -2018-04-17,129.40869126782408,118.19534937271276 -2018-04-18,130.22593704129008,118.7832833901688 -2018-04-19,130.18673450611948,119.03652256293017 -2018-04-20,130.73568473776322,119.50435366336548 -2018-04-23,131.27064638366213,120.07219326942878 -2018-04-24,131.09263391859227,120.19605849845385 -2018-04-25,129.55946034620104,119.51472427697053 -2018-04-26,130.26386670936844,120.40403134426342 -2018-04-27,130.71429090241088,121.05775731060895 -2018-04-30,131.72308427656472,121.8814880342848 -2018-05-02,131.71296111451431,122.074012762323 -2018-05-03,131.85754170866468,121.46554234266566 -2018-05-04,132.5755576891956,121.78323671162731 -2018-05-07,132.75024424230185,122.12257784994338 -2018-05-08,132.67846953304112,121.91306342643577 -2018-05-09,133.1530791633207,122.19344730299916 -2018-05-10,133.21630820597147,122.44337693482835 -2018-05-11,133.75802154671948,122.35483862969492 -2018-05-14,133.78691525153428,122.32702554954831 -2018-05-15,133.36199346075114,122.60255830748147 -2018-05-16,132.56777721435023,122.92003707117065 -2018-05-17,134.1843411478326,124.12063503083328 -2018-05-18,133.84620057349207,123.95703375009484 -2018-05-21,133.9966238312786,124.46482728777956 -2018-05-22,134.80722428760404,124.5220165862981 -2018-05-23,133.60972360624234,122.88272657877239 -2018-05-24,133.067469570522,122.49857188457668 -2018-05-25,132.34956413289103,122.36830317895969 -2018-05-28,131.6479431292241,121.62604968774437 -2018-05-29,131.15052335370092,120.06138066501515 -2018-05-30,131.68320680114104,119.82492636271435 -2018-05-31,133.05783265377295,119.18576453252312 -2018-06-01,133.8523821502741,120.66785673590229 -2018-06-04,134.06292245121895,120.83080042055974 -2018-06-05,134.3213191962008,120.56674864338477 -2018-06-06,134.037876263023,120.4919012730522 -2018-06-07,132.106092481574,120.28877954587287 -2018-06-08,134.73785313644868,120.32985235027543 -2018-06-11,134.77081149556088,120.85287840045906 -2018-06-12,134.35773772023035,120.3993958309056 -2018-06-13,134.62684191808958,120.38526290529622 -2018-06-14,135.70821584422362,122.0572278918624 -2018-06-15,135.32916185784148,121.47039346129586 -2018-06-18,134.32716594707776,120.33558745052271 -2018-06-19,132.1333001424343,119.01421819749471 -2018-06-20,131.13555992226213,118.60975348663378 -2018-06-21,130.27948551788836,117.36675675014298 -2018-06-22,131.08708927708955,118.94246476282186 -2018-06-25,128.07378642272235,116.65695185243204 -2018-06-26,128.75628778819046,116.60021532498565 -2018-06-27,130.8022385219854,117.61381883184853 -2018-06-28,130.10333439855688,116.47547689460713 -2018-06-29,130.82155194469644,117.53278359019652 -2018-07-02,126.91421731947494,116.50019603909402 -2018-07-03,126.93092729758193,117.38354162060355 -2018-07-04,126.70940883626112,117.46589205441752 -2018-07-05,124.32010474444901,118.4775012125102 -2018-07-06,127.70461409931809,118.68614243466438 -2018-07-09,127.95592605232024,119.17936105593118 -2018-07-10,127.65436701118004,119.9796878272821 -2018-07-11,127.67259103026207,118.20396280334722 -2018-07-12,129.45503942760905,119.3513493817681 -2018-07-13,129.30095463346464,119.86577278158082 -2018-07-16,129.4986212739071,119.4292906877604 -2018-07-17,129.43471480042896,119.71872998576688 -2018-07-18,128.54766350779374,120.26846952920762 -2018-07-19,129.25234162589115,119.5979586924015 -2018-07-20,129.503544459617,119.18399656928895 -2018-07-23,129.84776270672984,118.74089539360418 -2018-07-24,131.47118976447047,119.97593629554139 -2018-07-25,131.8807794521734,119.80417435524055 -2018-07-26,130.47833878377858,120.99946842520079 -2018-07-27,130.09715628037148,121.68852131543798 -2018-07-30,129.87139311641968,121.23504952614815 -2018-07-31,130.7389494000027,121.67836630710536 -2018-08-01,130.4041191279092,121.39290492637566 -2018-08-02,129.5208819998831,120.56740623946568 -2018-08-03,130.10100263639833,120.96480987765372 -2018-08-06,130.45440298779863,120.92507382594036 -2018-08-07,131.0807436124725,121.89937249163478 -2018-08-08,131.02147396182508,121.47083545210431 -2018-08-09,130.33944370325008,121.47856490112181 -2018-08-10,129.10183404013182,119.54520008223186 -2018-08-13,128.5822879129895,119.49308828787962 -2018-08-14,127.53470032313199,119.2963808175558 -2018-08-15,125.65672948464153,117.12854526487162 -2018-08-16,126.62214693876734,118.09555647235709 -2018-08-17,126.32661389001488,118.00526098425316 -2018-08-20,127.38401650507973,118.77180240941047 -2018-08-21,128.39136512886938,119.4109642396017 -2018-08-22,129.8038955617349,119.67611560366618 -2018-08-23,129.93679332945527,119.64786053271102 -2018-08-24,130.66788388310957,119.93862580314311 -2018-08-27,131.54232960033505,120.9674618225049 -2018-08-28,131.12750899681294,121.0975041425858 -2018-08-29,131.02418955701552,121.4582548844566 -2018-08-30,130.73861308629674,120.9444998609885 -2018-08-31,130.06561569093148,119.37232777477787 -2018-09-03,130.36134369211618,119.52576326692008 -2018-09-04,127.73602004597774,117.95602752028819 -2018-09-05,126.6590594755792,116.13503616940149 -2018-09-06,130.086643008235,115.77339066565001 -2018-09-07,131.20333103018618,115.95841233020678 -2018-09-10,130.62708128889466,116.34278262967497 -2018-09-11,131.89504535456294,116.65541027473392 -2018-09-12,132.07304240033653,117.72265637338347 -2018-09-13,132.62563480257367,117.63412884851367 -2018-09-14,132.96664832069263,118.17392898889425 -2018-09-17,133.05155071648977,118.09224693142487 -2018-09-18,133.01333462540066,118.42164866668077 -2018-09-19,133.80819349635482,119.08288847677134 -2018-09-20,134.12585756364714,120.36009098973705 -2018-09-21,133.53871406606945,121.30017309869295 -2018-09-24,132.35392726418675,120.9027694605049 -2018-09-25,132.81344172536376,120.96746182250486 -2018-09-26,133.98352980671814,121.70994169925626 -2018-09-27,134.60238521120505,122.32106406376478 -2018-09-28,133.7911529066148,121.28516697173012 -2018-10-01,134.0737765792544,121.57945738836683 -2018-10-02,133.53584403081808,120.7199685302544 -2018-10-03,134.12878486750657,121.23901666316125 -2018-10-04,132.73561355445509,119.46063969437517 -2018-10-05,131.85178983195075,118.32383933483183 -2018-10-08,130.2899952178336,117.0188129614559 -2018-10-09,130.41440959249357,117.42283568150829 -2018-10-10,128.32319006219487,114.9428252548373 -2018-10-11,124.82825529713777,112.73833680583589 -2018-10-12,124.78709495154237,112.50894357620797 -2018-10-15,124.81128041188084,112.4888491648152 -2018-10-16,127.08514056006858,114.21048960615488 -2018-10-17,126.17557185975271,113.59010699519443 -2018-10-18,125.45336327194991,112.96838763154477 -2018-10-19,124.83375224938614,112.25902472464237 -2018-10-22,124.77230066210012,111.56687789874546 -2018-10-23,122.56788387505154,109.67655867250103 -2018-10-24,123.63743322386888,109.354218009918 -2018-10-25,125.4895322746996,111.10301393532333 -2018-10-26,123.9809388006936,109.66949759982816 -2018-10-29,123.33226540617002,110.15477116680502 -2018-10-30,123.24000682182694,109.91588052492548 -2018-10-31,123.24000682182694,112.45286464484255 -2018-11-01,123.24000682182694,112.28374386912928 -2018-11-02,123.24000682182694,112.64472099653615 -2018-11-05,123.24000682182694,112.62838889714772 -2018-11-06,123.24000682182694,112.04994151167966 -2018-11-07,123.24000682182694,113.435334750363 -2018-11-08,123.24000682182694,113.2920542665534 -2018-11-09,123.24000682182694,112.74672385093434 -2018-11-12,123.24000682182694,111.69448387924763 -2018-11-13,123.24000682182694,112.63854390548032 -2018-11-14,123.24000682182694,111.90997056880222 -2018-11-15,123.24000682182694,111.13216376815916 -2018-11-16,123.24000682182694,110.94626890224893 -2018-11-19,123.24000682182694,110.06866920125033 -2018-11-20,123.24000682182694,108.73162544491491 -2018-11-21,123.24000682182694,109.84898898914649 -2018-11-22,123.24000682182694,109.02415867858112 -2018-11-23,123.24000682182694,109.2186669751259 -2018-11-26,123.24000682182694,110.27906760637502 -2018-11-27,123.24000682182694,110.01788337932369 -2018-11-28,123.24000682182694,110.0198777280939 -2018-11-29,123.24000682182694,110.52788687105108 -2018-11-30,123.24000682182694,110.47644345304344 -2018-12-03,123.24000682182694,111.58166842043583 -2018-12-04,123.24000682182694,110.66941017189016 -2018-12-05,123.24000682182694,109.16170406214341 -2018-12-06,123.24000682182694,105.54289892715889 -2018-12-07,123.24000682182694,106.26418480562802 -2018-12-10,123.24000682182694,104.70216772775 -2018-12-11,123.24000682182694,106.11119130429434 -2018-12-12,123.24000682182694,108.39074272890079 -2018-12-13,123.24000682182694,108.11409960381448 -2018-12-14,123.24000682182694,107.15989534951281 -2018-12-17,123.24000682182694,105.97143596668937 -2018-12-18,123.24000682182694,104.96048440467769 -2018-12-19,123.24000682182694,105.47644938218843 -2018-12-20,123.24000682182694,103.60003669601731 -2018-12-21,123.24000682182694,103.64242469258187 -2018-12-24,123.24000682182694,102.1413484449631 -2018-12-27,123.24000682182694,101.52801612641191 -2018-12-28,123.24000682182694,103.29713284874606 -2018-12-31,123.24000682182694,104.4440774363584 -2019-01-02,123.24000682182694,103.53226117862127 -2019-01-03,123.24000682182694,101.81238870051571 -2019-01-04,123.24000682182694,104.58604272800602 -2019-01-07,123.24000682182694,104.18973867670749 -2019-01-08,123.24000682182694,105.38415954531429 -2019-01-09,123.24000682182694,106.27412420868816 -2019-01-10,123.24000682182694,106.0992683327276 -2019-01-11,123.24000682182694,105.56232496220703 -2019-01-14,123.24000682182694,105.15189876556273 -2019-01-15,123.24000682182694,105.66896332996299 -2019-01-16,123.24000682182694,106.21142619545842 -2019-01-17,123.24000682182694,105.85000707724302 -2019-01-18,123.24000682182694,107.6506884114645 -2019-01-21,123.24000682182694,107.47074425107402 -2019-01-22,123.24000682182694,107.02366515811246 -2019-01-23,123.24000682182694,106.86580975788495 -2019-01-24,123.24000682182694,107.56303408794815 -2019-01-25,123.24000682182694,108.75215106685258 -2019-01-28,123.24000682182694,107.92997270113838 -2019-01-29,123.24000682182694,108.80426286120482 -2019-01-30,123.24000682182694,109.83264610949443 -2019-01-31,123.9256672479028,110.22917654632904 -2019-02-01,124.86050350571966,110.8151162150149 -2019-02-04,124.08494296442855,110.39409301922946 -2019-02-05,126.17310346802391,112.22987489180653 -2019-02-06,125.8248820722666,112.13515949561729 -2019-02-07,123.62466922656455,110.07109476056544 -2019-02-08,123.27168533022902,109.5429912062155 -2019-02-11,124.58268412612284,110.70937260913959 -2019-02-12,125.9013569081359,111.63399582006053 -2019-02-13,127.13632104696124,112.02963149501446 -2019-02-14,126.4328618870768,111.77021523119726 -2019-02-15,127.96755266572742,113.77202394382788 -2019-02-18,127.8122628112739,114.11092309133542 -2019-02-19,128.0460758374207,113.9338572613322 -2019-02-20,128.28353112585353,114.71608397006058 -2019-02-21,128.3919951473914,114.71960911626522 -2019-02-22,129.21698350052296,115.15543361400465 -2019-02-25,129.12326138305494,115.50868129239402 -2019-02-26,129.41958589803332,115.66035960156572 -2019-02-27,128.21765542930774,115.36517442304833 -2019-02-28,128.6966352562398,115.70031125855154 -2019-03-01,129.62335901555136,116.24475769255352 -2019-03-04,129.6461582974533,116.71678231553805 -2019-03-05,129.3312739785917,116.95854050754124 -2019-03-06,128.9638568050161,116.76624216503912 -2019-03-07,128.19984661291497,116.30503014646817 -2019-03-08,127.3081734627543,115.49477475232071 -2019-03-11,127.88489772378647,116.26175816828656 -2019-03-12,127.71195572161875,116.3564735644758 -2019-03-13,128.67867150091132,117.15414839097555 -2019-03-14,129.31057427359696,118.112330562554 -2019-03-15,130.7733755258381,119.33854242858422 -2019-03-18,130.72730277622918,119.50435366336531 -2019-03-19,131.4088373253675,119.79290897975474 -2019-03-20,130.21623302883881,118.83826273464453 -2019-03-21,130.6990778614651,118.75414433759643 -2019-03-22,127.91286115622195,116.34918610626686 -2019-03-25,127.9970621529041,116.14430719611701 -2019-03-26,128.84555873691897,117.17622637087489 -2019-03-27,128.7031355704923,117.04067533608277 -2019-03-28,128.4247618122237,116.93690451845045 -2019-03-29,129.9517743867179,118.12888904747852 -2019-04-01,131.07640769653509,119.34317794194202 -2019-04-02,131.45444209181545,119.7392663879681 -2019-04-03,132.54890380829318,120.74248850096231 -2019-04-04,132.16846194078772,120.62966226188689 -2019-04-05,133.01315780968636,120.90343783684956 -2019-04-08,132.95236344338073,120.80584411027306 -2019-04-09,131.7087971930934,120.02516975950635 -2019-04-10,131.70498468841032,120.32233850653033 -2019-04-11,132.63608280126905,121.11362063670178 -2019-04-12,132.49856335495284,121.48850430418197 -2019-04-15,132.71710825406495,121.62162977965897 -2019-04-16,133.04318814916323,122.0618634052201 -2019-04-17,133.58302031164348,122.82178574851307 -2019-04-18,132.22652070700664,123.20351488339367 -2019-04-23,134.06102525236815,123.45321812968679 -2019-04-24,133.99232045105575,123.10814189112344 -2019-04-25,133.49748623799871,122.70212482230083 -2019-04-26,133.82262549176264,122.96021511369244 -2019-04-29,133.84255914115982,123.216763827386 -2019-04-30,134.51846862019363,123.33665113913429 -2019-05-02,131.95998672352505,122.28683672676269 -2019-05-03,131.95884636156143,122.50717453494752 -2019-05-06,130.5595503832177,121.06504476881778 -2019-05-07,129.38573249985336,119.12726004184252 -2019-05-08,129.76069829989987,119.60943967315967 -2019-05-09,127.82476248779805,117.30384313164073 -2019-05-10,128.04957382656562,117.61911194128726 -2019-05-13,126.00857482058339,116.18691079795406 -2019-05-14,128.38167344220054,117.92622009137139 -2019-05-15,129.9747969337928,118.65279907927928 -2019-05-16,131.31961996217132,120.28326005089798 -2019-05-17,130.68606644254004,120.06513219675581 -2019-05-20,128.76719918340115,118.30683885909887 -2019-05-21,129.86928710835085,118.90007676625731 -2019-05-22,130.07319568771516,118.75701188772015 -2019-05-23,127.60099512706991,116.60198328821977 -2019-05-24,128.7664315946575,117.37779574009262 -2019-05-27,128.94235078456856,117.81229426540645 -2019-05-28,128.58052756615174,117.29346173777206 -2019-05-29,127.07229170497575,115.2938629791841 -2019-05-30,127.92256544939069,115.8853329231084 -2019-05-31,127.92256544939069,114.97394787591617 -2019-06-03,127.92256544939069,115.72084766075288 -2019-06-04,127.92256544939069,116.31253320994963 -2019-06-05,127.92256544939069,116.83666962728641 -2019-06-06,127.92256544939069,116.53707532094732 -2019-06-07,127.92256544939069,118.42738376692813 -2019-06-10,127.92256544939069,118.83472680817633 -2019-06-11,127.92256544939069,119.40765469866956 -2019-06-12,127.92256544939069,118.6673739956972 -2019-06-13,127.92256544939069,118.68304849900463 -2019-06-14,127.92256544939069,118.50620905453749 -2019-06-17,127.92256544939069,119.02129005043119 -2019-06-18,127.92256544939069,121.64370775955832 -2019-06-19,127.92256544939069,121.83623248759655 -2019-06-20,127.92256544939069,122.21419931047284 -2019-06-21,127.92256544939069,122.05436034173873 -2019-06-24,127.92256544939069,121.90820152754186 -2019-06-25,127.92256544939069,121.75056173258679 -2019-06-26,127.92256544939069,121.44479033519188 -2019-06-27,127.92256544939069,121.2878081363178 -2019-06-28,128.795529125815,122.28927306634151 -2019-07-01,128.23612950058666,122.92820851099667 -2019-07-02,127.54088952879744,123.1249159813205 -2019-07-03,127.17103597665798,124.05197553182015 -2019-07-04,127.40708928738627,124.09436352838469 -2019-07-05,125.87898525153358,123.49804246583017 -2019-07-08,125.71462550065347,123.39802317993855 -2019-07-09,123.39611822596737,123.02071395314324 -2019-07-10,123.21075957637636,122.92113665806015 -2019-07-11,121.83152173872266,122.57584481422434 -2019-07-12,122.88736850109822,123.0374880433402 -2019-07-15,123.44999357412503,123.15560739185437 -2019-07-16,124.72903305635282,123.95416619997117 -2019-07-17,123.74033926890475,123.01210052250867 -2019-07-18,122.76867620314803,122.54492701815437 -2019-07-19,124.30798235418936,122.58444746459526 -2019-07-22,125.4587087204832,122.9085560904124 -2019-07-23,128.48812734549824,124.03762700093826 -2019-07-24,129.1869473543705,123.76628776555432 -2019-07-25,128.23310510118907,123.15207146538607 -2019-07-26,129.40464368290827,123.85856682216482 -2019-07-29,129.60692770978207,123.66097537022394 -2019-07-30,127.90548579681149,121.67328880293908 -2019-07-31,128.5747717682385,121.84616111039307 -2019-08-01,127.67865128431613,122.69638972205358 -2019-08-02,126.09304674456756,118.31589428054195 -2019-08-05,123.62180700658502,115.72283122925948 -2019-08-06,123.56957043821603,115.57049532400679 -2019-08-07,124.58042957500433,116.27389674512582 -2019-08-08,126.40413456354585,118.95527171600563 -2019-08-09,124.99215636474959,117.6297089404284 -2019-08-12,125.04336655669967,117.2409187328749 -2019-08-13,125.87805347586963,118.40574777783733 -2019-08-14,123.57402145567619,115.938091533278 -2019-08-15,123.62195699882878,115.62083915512488 -2019-08-16,125.39641268787767,117.03073593302267 -2019-08-19,125.87625527638573,118.59319500170923 -2019-08-20,125.099073826637,117.99885750766128 -2019-08-21,126.9914933784513,120.00441775203261 -2019-08-22,125.59400168241248,118.96167519259751 -2019-08-23,124.49655555619553,117.60653137363953 -2019-08-26,124.78120811759514,118.13971243215576 -2019-08-27,125.0584318416947,118.9360612862299 -2019-08-28,124.50413262891357,118.53225417144996 -2019-08-29,125.20612871009386,120.32433285530051 -2019-08-30,125.42361309324697,120.99792684750271 -2019-09-02,124.75778105790549,121.27522756867 -2019-09-03,124.38130958381454,120.67977970746891 -2019-09-04,124.71564909908051,122.13692638082509 -2019-09-05,124.53411765963577,123.49031301681256 -2019-09-06,123.89576578121351,123.72478375060678 -2019-09-09,123.19986256347524,123.39273007049967 -2019-09-10,124.03173942337796,123.48677709034429 -2019-09-11,124.65819729075461,124.03541704689552 -2019-09-12,124.97758905619729,124.58294663629358 -2019-09-13,125.70479688586558,124.86113133907794 -2019-09-16,125.03954816367155,123.68592090024683 -2019-09-17,125.2677356894229,123.979111729994 -2019-09-18,125.39395031291484,124.0925955651504 -2019-09-19,125.8867226006805,124.9410562135768 -2019-09-20,126.3348769400158,125.64092170822757 -2019-09-23,125.16210371209706,124.31580092345887 -2019-09-24,125.32492175217031,124.2621583316722 -2019-09-25,123.7333732482554,123.27901984980714 -2019-09-26,124.80816447805357,124.09082760191627 -2019-09-27,125.7902585618793,124.53261358543907 -2019-09-30,127.0858633066303,125.35413435507226 -2019-10-01,126.7514906326442,123.58436003665713 -2019-10-02,123.00500097762877,119.72380748993304 -2019-10-03,123.19949796391124,120.0770551683224 -2019-10-04,125.14546503516044,121.17101476022906 -2019-10-07,125.98936667070639,121.90599157349904 -2019-10-08,124.54227889979082,120.47114926557828 -2019-10-09,125.21380908487374,121.40990540210859 -2019-10-10,126.61514973894403,122.9533696462919 -2019-10-11,129.03447366742353,125.08235312887979 -2019-10-14,128.5648236947704,124.58780853518738 -2019-10-15,129.6248110105474,125.88974097290358 -2019-10-16,129.05229766363468,125.77604153247474 -2019-10-17,129.0247992931001,125.24992154663137 -2019-10-18,129.0062508904225,124.43701420763271 -2019-10-21,128.26637598163637,124.7041599204674 -2019-10-22,128.82162212353265,124.91036480304285 -2019-10-23,128.34918146900634,124.81653338847067 -2019-10-24,128.4674126177511,125.49852520603498 -2019-10-25,128.2471496212466,126.33351052493296 -2019-10-28,127.34064184262814,126.51940539084319 -2019-10-29,127.04630517826126,126.73069855784854 -2019-10-30,127.34103423858201,127.29876454944791 -2019-10-31,126.56599294852599,126.50373088753574 -2019-11-01,128.35216068577517,127.2108946206591 -2019-11-04,129.6015389001947,128.5887740155974 -2019-11-05,130.61724038233362,129.08752291210268 -2019-11-06,129.79422336363973,129.52577296915723 -2019-11-07,130.10976954461702,130.06116398171613 -2019-11-08,130.35832507961464,130.0326825252249 -2019-11-11,130.4516613080653,130.12363560940983 -2019-11-12,132.7418119831563,130.69612150909452 -2019-11-13,132.83149649743143,130.41661083388456 -2019-11-14,132.13057108056333,130.2839273492161 -2019-11-15,133.6579820208464,131.1270841079401 -2019-11-18,133.55666092378306,130.91778528970494 -2019-11-19,133.64138767121014,130.45988281206616 -2019-11-20,133.6412267462684,130.1282711227676 -2019-11-21,131.64606977018883,129.845235301353 -2019-11-22,132.60039849327976,130.1084030969109 -2019-11-25,133.75208560440163,130.80893696790628 -2019-11-26,134.89639749497218,130.91403375796418 -2019-11-27,135.06621836813548,130.8526509368964 -2019-11-28,135.1205171825528,130.54091805371812 -2019-11-29,134.8871113841199,130.37422283731996 -2019-12-02,132.72927415879207,127.75953457721032 -2019-12-03,131.71778801635523,126.4454527823913 -2019-12-04,134.31123426758464,128.0452223434761 -2019-12-05,135.06474263873383,128.0864999728875 -2019-12-06,137.39056454697499,129.6399144003946 -2019-12-09,137.46155482714437,128.87468816739923 -2019-12-10,137.64355320877885,129.1126840473981 -2019-12-11,138.03630134332647,129.39638824515728 -2019-12-12,139.83323979785814,129.9125688279405 -2019-12-13,141.390389197732,130.6800050149785 -2019-12-16,143.0244608444714,132.28375249334007 -2019-12-17,142.60163749923234,131.76711913948472 -2019-12-18,142.47221316282787,131.57593116413574 -2019-12-19,142.87941931267895,131.85587304989062 -2019-12-20,143.77686918249995,132.94321355993293 -2019-12-23,143.66602956655856,133.11631225292297 -2019-12-24,144.3931707964313,133.12027938993612 -2019-12-25,144.3931707964313,133.12027938993612 -2019-12-27,144.1750819595405,133.29337808292618 -2019-12-30,143.06969992014618,132.07533765672198 -2019-12-31,143.06092263556886,131.98348981065638 -2020-01-02,146.20736749113232,133.3841155618386 -2020-01-03,145.4781170443204,133.44284643805517 -2020-01-06,143.5507998187914,132.76791569316376 -2020-01-07,145.25004323984103,132.74054460382567 -2020-01-08,145.79874597999327,133.15229677289557 -2020-01-09,146.4824205354321,133.40729312862743 -2020-01-10,145.0550882583238,133.28719021160668 -2020-01-13,145.43862312886733,133.26578060805195 -2020-01-14,145.822750778351,133.3706510125738 -2020-01-15,144.32865635913092,133.18783930205967 -2020-01-16,144.77053506410599,133.32957820817123 -2020-01-17,145.82556492791664,134.69157827479324 -2020-01-20,145.26870217917784,134.20188479973106 -2020-01-21,143.87861476877453,133.4832508661131 -2020-01-22,144.49543960697054,132.71029518410026 -2020-01-23,145.53479237317313,131.84506044547692 -2020-01-24,146.73649969600459,133.00348601384746 -2020-01-27,142.16904405843007,129.4436381406156 -2020-01-28,144.3516072082299,130.83013096618848 -2020-01-29,144.70148199128295,131.47194474123089 -2020-01-30,143.12574275048615,129.63682046473483 -2020-01-31,143.09467287148433,128.19225435902638 -2020-02-03,143.50133822592036,128.77003336814983 -2020-02-04,143.48507388072989,131.03391028944884 -2020-02-05,143.87194993758658,132.14553873343314 -2020-02-06,144.85703759255887,133.3108205494677 -2020-02-07,144.4121624049114,133.1246992980214 -2020-02-10,144.12937191215514,132.81383961619656 -2020-02-11,146.23422668453125,133.67686440077722 -2020-02-12,147.04835112783917,134.78010579966303 -2020-02-13,148.27865382903803,134.5242254623141 -2020-02-14,148.57260199134183,133.9989894580878 -2020-02-17,150.26560453323387,134.3654860804695 -2020-02-18,150.5520950095087,133.7223463330015 -2020-02-19,151.03085324909608,134.9238390545448 -2020-02-20,149.74119149497707,133.84333323163932 -2020-02-21,150.27195505957238,133.1240417019404 -2020-02-24,145.57874428057198,127.87279202683061 -2020-02-25,142.67567240070534,125.39586475555573 -2020-02-26,143.89596343805619,125.50337632466515 -2020-02-27,142.72191745881545,121.33174849084378 -2020-02-28,142.72191745881545,117.23186331143164 -2020-03-02,142.72191745881545,117.75334778391722 -2020-03-03,142.72191745881545,119.07029712885989 -2020-03-04,142.72191745881545,120.65373459055627 -2020-03-05,142.72191745881545,118.3622601943831 -2020-03-06,142.72191745881545,113.46116426200295 -2020-03-09,142.72191745881545,103.94114579756743 -2020-03-10,142.72191745881545,102.3669793625866 -2020-03-11,142.72191745881545,101.78500683091393 -2020-03-12,142.72191745881545,89.28909120329399 -2020-03-13,142.72191745881545,90.92506627975571 -2020-03-16,142.72191745881545,85.69479499765573 -2020-03-17,142.72191745881545,88.1304392493874 -2020-03-18,142.72191745881545,82.89928398567035 -2020-03-19,142.72191745881545,85.12165150189007 -2020-03-20,142.72191745881545,89.38932609445808 -2020-03-23,142.72191745881545,86.42005879340165 -2020-03-24,142.72191745881545,93.67024963101842 -2020-03-25,142.72191745881545,97.85622599572163 -2020-03-26,142.72191745881545,100.31306963586738 -2020-03-27,142.72191745881545,96.07211392668829 -2020-03-30,142.72191745881545,96.66865059451527 -2020-03-31,142.72191745881545,97.05745158233238 -2020-04-01,142.72191745881545,92.88736532620905 -2020-04-02,142.72191745881545,93.1902691734803 -2020-04-03,142.72191745881545,91.72473545502565 -2020-04-06,142.72191745881545,95.95399457817409 -2020-04-07,142.72191745881545,97.98803627903665 -2020-04-08,142.72191745881545,98.08694519777514 -2020-04-09,142.72191745881545,99.50214586537531 -2020-04-14,142.72191745881545,99.87879749608962 -2020-04-15,142.72191745881545,96.12134739065326 -2020-04-16,142.72191745881545,96.04274848857999 -2020-04-17,142.72191745881545,99.32904717238524 -2020-04-20,142.72191745881545,99.97571206605788 -2020-04-21,142.72191745881545,96.20391342973967 -2020-04-22,142.72191745881545,97.40362740778524 -2020-04-23,142.72191745881545,98.26908853194467 -2020-04-24,142.72191745881545,96.99562677045607 -2020-04-27,142.72191745881545,99.46703454675611 -2020-04-28,142.72191745881545,100.89173262660789 -2020-04-29,142.72191745881545,103.1286696691137 -2020-04-30,142.72191745881545,100.9445020170411 -2020-05-04,142.72191745881545,96.66247350345944 -2020-05-05,142.72191745881545,98.97845143884707 -2020-05-06,142.72191745881545,97.8800719388551 -2020-05-07,142.72191745881545,99.38270054443555 -2020-05-08,142.72191745881545,100.446863487689 -2020-05-11,142.72191745881545,99.13499164691264 -2020-05-12,142.72191745881545,98.7437650997804 -2020-05-13,142.72191745881545,95.92772307572554 -2020-05-14,142.72191745881545,94.3420756599865 -2020-05-15,142.72191745881545,94.44142656953352 -2020-05-18,142.72191745881545,99.3142566506949 -2020-05-19,142.72191745881545,98.4271703177083 -2020-05-20,142.72191745881545,99.28423361650563 -2020-05-21,142.72191745881545,98.14656005560884 -2020-05-22,142.72191745881545,98.12690763502462 -2020-05-25,142.72191745881545,100.23204517447904 -2020-05-26,142.72191745881545,101.69647930604418 -2020-05-27,142.72191745881545,103.5179126477394 -2020-05-28,142.72191745881545,105.3426555303668 -2020-05-29,144.20578527449535,103.66582864490678 -2020-06-01,143.73819709932562,105.15255636164372 -2020-06-02,146.860696988041,107.27624673479285 -2020-06-03,148.52607340284706,110.88400209956409 -2020-06-04,148.40799537396092,110.65439326466372 -2020-06-05,149.40944862361053,114.756704003391 -2020-06-08,149.609112387847,114.26502695982224 -2020-06-09,148.32091885003442,112.48973314643227 -2020-06-10,147.38856140072485,111.56930345806059 -2020-06-11,143.62942586889264,106.31872215929539 -2020-06-12,142.27539535648145,106.84107983313442 -2020-06-15,143.97600058048744,106.32137410414657 -2020-06-16,145.67362772400492,109.3403114698447 -2020-06-17,146.80696922969955,110.3009299810019 -2020-06-18,146.94218526877225,109.47918282583262 -2020-06-19,146.05924073921867,109.93620132185431 -2020-06-22,145.51503489828292,109.25730343994974 -2020-06-23,145.32783608842135,110.78024206219538 -2020-06-24,142.48406484565803,107.54978514395582 -2020-06-25,142.78174757353352,108.59231209811846 -2020-06-26,143.40185010353244,108.39493625145003 -2020-06-29,145.59212963783702,109.18576561054935 -2020-06-30,145.86951073520515,108.97669317785027 -2020-07-01,145.28999871941033,108.7768809916031 -2020-07-02,148.0934668163211,111.48010755684616 -2020-07-03,147.80699250198967,110.5475392916353 -2020-07-06,148.98418470626783,112.18947046374858 -2020-07-07,148.91524416784745,111.35536912646765 -2020-07-08,147.06369523040553,109.9732854287165 -2020-07-09,145.6310395416095,108.64595468990514 -2020-07-10,146.54130208308146,109.73815709884127 -2020-07-13,148.21542620471007,111.63134387520934 -2020-07-14,146.1203497518463,110.55460036430817 -2020-07-15,149.39337741285533,112.79595731489931 -2020-07-16,149.61636167422395,112.2727048791796 -2020-07-17,149.76837033829585,111.92255113644994 -2020-07-20,150.39043137591827,112.44712954459524 -2020-07-21,149.9035589759058,112.69218649726697 -2020-07-22,150.14712297962546,111.20943669780682 -2020-07-23,150.77092798851285,111.13524692355524 -2020-07-24,148.31481230272428,109.42796579336103 -2020-07-27,149.17561653721535,109.05683365762155 -2020-07-28,148.57471834559118,108.82103695140174 -2020-07-29,150.98034476028045,109.47896722056012 -2020-07-30,147.75821787448888,107.1431104790522 -2020-07-31,147.65228162135966,105.61421037102318 -2020-08-03,149.86438436020057,107.65068841146446 -2020-08-04,149.52796861882146,107.95072470861207 -2020-08-05,149.3568122353479,108.91817790690607 -2020-08-06,147.65315733843798,107.85379935838016 -2020-08-07,148.1361509884044,107.95072470861207 -2020-08-10,147.2865523570131,108.3920579210627 -2020-08-11,148.3334748478539,111.00786732858911 -2020-08-12,150.10223831083272,112.00843749673213 -2020-08-13,149.36391173109618,111.32556169755075 -2020-08-14,148.07000962899068,109.57147266270668 -2020-08-17,148.4830344712582,109.77039008707315 -2020-08-18,147.99002788347659,109.02239071534693 -2020-08-19,148.55651561714836,109.88718346316175 -2020-08-20,147.3223739607559,108.43026317534164 -2020-08-21,146.71313480646558,108.10107704535817 -2020-08-24,148.86062580634626,110.56409777655972 -2020-08-25,148.27517317040775,110.57248482165821 -2020-08-26,149.67048947482027,111.4591399440999 -2020-08-27,148.12262205544204,110.74248957898855 -2020-08-28,147.8655857763718,110.45480746395258 -2020-08-31,147.8655857763718,109.2246284609092 -2020-09-01,147.8655857763718,109.02327469696398 -2020-09-02,147.8655857763718,111.09065975321161 -2020-09-03,147.8655857763718,110.60008229653238 -2020-09-04,147.8655857763718,109.61871177790144 -2020-09-07,147.8655857763718,111.57593332018847 -2020-09-08,147.8655857763718,109.80527502015627 -2020-09-09,147.8655857763718,111.33881064154308 -2020-09-10,147.8655857763718,110.91822943656618 -2020-09-11,147.8655857763718,111.14364474891732 -2020-09-14,147.8655857763718,111.53530250659445 -2020-09-15,147.8655857763718,111.88966055213697 -2020-09-16,147.8655857763718,112.03294103594659 -2020-09-17,147.8655857763718,111.26197970270395 -2020-09-18,147.8655857763718,109.90816185617157 -2020-09-21,147.8655857763718,105.79856365923534 -2020-09-22,147.8655857763718,105.37466213306264 -2020-09-23,147.8655857763718,106.02419457685893 -2020-09-24,147.8655857763718,105.14903121543907 -2020-09-25,147.8655857763718,104.42134186037804 -2020-09-28,147.8655857763718,106.92961813826777 -2020-09-29,147.8655857763718,106.68234045128976 -2020-09-30,147.8655857763718,106.05025047403504 -2020-10-01,147.8655857763718,106.50505901601409 -2020-10-02,147.8655857763718,106.52360106944516 -2020-10-05,147.8655857763718,107.5610505194415 -2020-10-06,147.8655857763718,108.08186661558247 -2020-10-07,147.8655857763718,107.7846978685585 -2020-10-08,147.8655857763718,108.44571129311298 -2020-10-09,147.8655857763718,109.21557303946611 -2020-10-12,147.8655857763718,109.932665395386 -2020-10-13,147.8655857763718,109.23323111128012 -2020-10-14,147.8655857763718,109.10187359903725 -2020-10-15,147.8655857763718,106.80045979980393 -2020-10-16,147.8655857763718,108.97381484746293 -2020-10-19,147.8655857763718,109.12306759731953 -2020-10-20,147.8655857763718,108.82854001488312 -2020-10-21,147.8655857763718,107.16541484448757 -2020-10-22,147.8655857763718,107.10866753677756 -2020-10-23,147.8655857763718,108.39493625144996 -2020-10-26,147.8655857763718,106.33020314005351 -2020-10-27,147.8655857763718,104.44341984027734 -2020-10-28,147.8655857763718,100.92109806471619 -2020-10-29,147.8655857763718,100.88908068175671 -2020-10-30,147.8655857763718,101.43154354725212 -2020-11-02,147.8655857763718,103.57089764344506 -2020-11-03,147.8655857763718,106.09815796557443 -2020-11-04,147.8655857763718,108.68658550349912 -2020-11-05,147.8655857763718,110.03643621301835 -2020-11-06,147.8655857763718,109.52620633575488 -2020-11-09,147.8655857763718,117.81516181552996 -2020-11-10,147.8655857763718,119.63991547842099 -2020-11-11,147.8655857763718,120.21923606524247 -2020-11-12,147.8655857763718,118.39470878788752 -2020-11-13,147.8655857763718,118.7830677848961 -2020-11-16,147.8655857763718,120.79922502840856 -2020-11-17,147.8655857763718,121.05356378805945 -2020-11-18,147.8655857763718,121.68168662830101 -2020-11-19,147.8655857763718,120.86943688538334 -2020-11-20,147.8655857763718,121.33815196743568 -2020-11-23,147.8655857763718,121.25557514808563 -2020-11-24,147.8655857763718,122.71868330722518 -2020-11-25,147.8655857763718,123.00282949579291 -2020-11-26,147.8655857763718,122.9034785862459 -2020-11-27,147.8655857763718,123.59650939375986 -2020-11-30,144.25292492135713,121.83843166137538 -2020-12-01,147.18989983241937,123.23133874380375 -2020-12-02,148.13342373907903,123.26157738326549 -2020-12-03,147.26597297095313,123.07060501318897 -2020-12-04,149.40133497825153,123.83869879630797 -2020-12-07,148.19254205232494,123.04896902409817 -2020-12-08,147.54212328566354,122.7683587619987 -2020-12-09,146.36279070690264,122.46257658434017 -2020-12-10,146.42528641188233,122.52505899229747 -2020-12-11,143.396000800409,121.5955738824827 -2020-12-14,144.0108581774622,122.04353695706132 -2020-12-15,144.31522810307203,122.09807431072868 -2020-12-16,144.3451644964776,122.48157140884341 -2020-12-17,143.21386115508093,122.52086546974823 -2020-12-18,143.5796474102194,122.04353695706132 -2020-12-21,138.69150109755836,119.07404866060062 -2020-12-22,140.4237990546002,120.69722217401035 -2020-12-23,143.46009316059573,122.03801746208649 -2020-12-24,143.3407128481441,121.91482060940602 -2020-12-28,143.76320807212764,123.38013872258821 -2020-12-29,143.67147333556298,123.89698768171603 -2020-12-30,143.19620411018678,123.62366487782552 -2020-12-31,142.36776385313607,122.5639218426574 -2021-01-04,143.34081022936658,123.392945675772 -2021-01-05,141.9061602877584,122.855129103898 -2021-01-06,140.71410975015164,124.31227577725419 -2021-01-07,141.25889427556461,125.17883648830312 -2021-01-08,143.65824677692575,125.99637934065953 -2021-01-11,142.55955324828588,125.01501960229221 -2021-01-12,141.80314157393693,124.76200681506693 -2021-01-13,142.11587902036644,125.02031271173097 -2021-01-14,153.09119029222515,125.42809774378769 -2021-01-15,151.33907582812844,123.89477772767334 -2021-01-18,180.43170304000347,124.01797458035382 -2021-01-19,180.1121767840625,123.60599602574786 -2021-01-20,181.80177869190473,124.26458389098721 -2021-01-21,181.7882438792387,123.43335010382994 -2021-01-22,180.81301255357272,122.74407082805666 -2021-01-25,178.19524855737276,120.81865106345666 -2021-01-26,179.88350759902104,121.94816396479105 -2021-01-27,177.11683429963057,120.5373832052762 -2021-01-28,178.3084054841352,121.66115022609969 -2021-01-29,178.3084054841352,119.20364898987296 -2021-02-01,178.3084054841352,120.58286513750049 -2021-02-02,178.3084054841352,122.82222773932142 -2021-02-03,178.3084054841352,122.82090176689582 -2021-02-04,178.3084054841352,123.82523424704316 -2021-02-05,178.3084054841352,124.94502335058985 -2021-02-08,178.3084054841352,125.53605130370563 -2021-02-09,178.3084054841352,125.65770657868806 -2021-02-10,178.3084054841352,125.1998041010493 -2021-02-11,178.3084054841352,125.17816811195848 -2021-02-12,178.3084054841352,125.92550988760372 -2021-02-15,178.3084054841352,127.74871119253307 -2021-02-16,178.3084054841352,127.75488828358888 -2021-02-17,178.3084054841352,127.29809617310326 -2021-02-18,178.3084054841352,126.46995632160571 -2021-02-19,178.3084054841352,127.46831653570605 -2021-02-22,178.3084054841352,127.33342309699492 -2021-02-23,178.3084054841352,127.60718789169397 -2021-02-24,178.3084054841352,128.00768546554175 -2021-02-25,178.3084054841352,127.69661017844446 -2021-02-26,175.90932939744096,125.9155812648072 -2021-03-01,177.6612708813941,127.89310204349584 -2021-03-02,179.94250691770702,128.26710172935896 -2021-03-03,184.73092317654277,128.71594878555464 -2021-03-04,183.57204190173263,128.7289713440109 -2021-03-05,183.4973402326262,127.66922830884275 -2021-03-08,190.12666438225824,130.3260997405081 -2021-03-09,188.32765203877656,130.81137330748496 -2021-03-10,189.08138009193001,132.25923817386195 -2021-03-11,187.27028866611332,133.21322682289116 -2021-03-12,189.546650670826,133.49560504822475 -2021-03-15,188.15574482690948,133.2620290763112 -2021-03-16,186.36962379790856,133.69166570273117 -2021-03-17,187.90086889792792,133.67819037320277 -2021-03-18,191.89646226136804,133.85415661631646 -2021-03-19,188.45700086128812,132.42283945460034 -2021-03-22,187.16267039456503,131.77198103837844 -2021-03-23,186.01827092370647,131.26020958341692 -2021-03-24,187.20866058290068,131.30414993794315 -2021-03-25,186.87796633396152,131.417191782291 -2021-03-26,189.0468694490407,132.22082809457413 -2021-03-29,186.89857733807474,132.81030368972822 -2021-03-30,192.67419114053263,134.41162560877467 -2021-03-31,192.55620742916722,133.95218155343787 -2021-04-01,192.29867173833836,134.7410273440306 -2021-04-06,192.308060543069,135.3675978263105 -2021-04-07,192.72092027524707,135.35259169934767 -2021-04-08,193.83978532541738,136.12664696825001 -2021-04-09,193.45387482112352,136.20811342044692 -2021-04-12,193.43458000954746,136.0374510670356 -2021-04-13,193.29204917979084,136.53243765153653 -2021-04-14,192.6604478268245,137.07290616826174 -2021-04-15,193.16022607795168,137.6372206281204 -2021-04-16,195.1090049200571,138.80580120482352 -2021-04-19,196.3240696581045,139.01819395871843 -2021-04-20,194.63791720515317,136.1131716387216 -2021-04-21,196.88926148211252,137.11639375171578 -2021-04-22,196.305050081969,138.36887712019455 -2021-04-23,196.13065825942314,138.16267223761912 -2021-04-26,196.2164674296098,138.55080484909163 -2021-04-27,196.8647802345862,138.51194199873171 -2021-04-28,197.0069159692959,139.24537723430365 -2021-04-29,196.64049075025292,139.1480098932632 -2021-04-30,197.28701182178986,138.41745298807854 -2021-05-03,198.39313205817274,139.26568725096882 -2021-05-04,196.77871513225818,138.02601083567384 -2021-05-05,199.68332148585344,139.9626959757596 -2021-05-06,203.8736746696132,140.35170178858553 -2021-05-07,204.50356165455233,140.97915625248248 -2021-05-10,207.38050195823047,140.98976403188726 -2021-05-11,204.00431345591673,138.3713134597733 -2021-05-12,206.26191009211354,138.63536523694827 -2021-05-13,206.6793739998339,138.83362506523378 -2021-05-14,209.4238121341815,140.97099559292013 -2021-05-17,209.73856544565052,140.57822746808984 -2021-05-18,209.9979318926028,140.276196822172 -2021-05-19,208.59568735007727,138.26444870648123 -2021-05-20,210.1622689936139,140.05343345467205 -2021-05-21,210.64560584390236,140.9990350586028 -2021-05-24,211.20463303683977,141.4865185796223 -2021-05-25,211.5368950964161,141.0842530425404 -2021-05-26,210.7605471369438,141.1136184806487 -2021-05-27,212.90217333809673,142.0874751555346 -2021-05-28,214.75156478332406,143.15604722660973 -2021-05-31,214.49199899534094,142.3404879427599 -2021-06-01,214.7852184867371,143.2728406026983 -2021-06-02,215.2536511574748,143.98198790432824 -2021-06-03,216.78280344123908,143.68172522164454 -2021-06-04,217.28700844257736,143.85261396059195 -2021-06-07,217.96697845652443,144.46858744373068 -2021-06-08,218.3870985382469,144.63306192582257 -2021-06-09,217.13707027026894,144.9077214824023 -2021-06-10,217.52736985508494,144.53327980573064 -2021-06-11,217.69178360488547,145.7292422520355 -2021-06-14,218.0249570138443,146.07564446302445 -2021-06-15,218.5533757580254,146.58718953244988 -2021-06-16,217.08406265221421,146.8770708212649 -2021-06-17,218.1899966604502,147.17754910922108 -2021-06-18,215.1545525724723,145.03378588520644 -2021-06-21,216.28197970210098,145.77074626698302 -2021-06-22,216.35520992053958,145.96856410445997 -2021-06-23,215.32847048414308,144.6343878982482 -2021-06-24,218.8290531085978,146.4023942534292 -2021-06-25,218.5327269632322,146.2195933231787 -2021-06-28,216.18563388065695,144.78783417065404 -2021-06-29,216.71707425361822,144.99559141119116 -2021-06-30,215.85831424004502,143.679741653138 -2021-07-01,215.56026217887808,144.69510234297138 -2021-07-02,216.4077762996091,144.67390834468912 -2021-07-05,216.63155647201845,144.99801697050628 -2021-07-06,217.35481066491351,143.67201220412053 -2021-07-07,220.84103812358447,144.11887569180962 -2021-07-08,219.3022190193922,141.22687593026905 -2021-07-09,221.51332743127253,144.1564017894803 -2021-07-12,224.47396362498353,144.81498965471968 -2021-07-13,224.41408138179702,144.79777357371418 -2021-07-14,224.12720523483583,144.79577922494397 -2021-07-15,222.06388944491644,143.36026854067862 -2021-07-16,221.34442385706788,142.62551811294472 -2021-07-19,219.72250441640603,139.0023038501385 -2021-07-20,219.70090899462897,140.12562888015344 -2021-07-21,220.63958074022727,142.72265906844908 -2021-07-22,223.98758821898505,143.1004102860529 -2021-07-23,225.74093806601533,145.02627204146143 -2021-07-26,223.75417413918484,145.24220072182456 -2021-07-27,222.67314892063675,144.21159673922867 -2021-07-28,224.16455272566662,145.9202146221121 -2021-07-29,225.09355596555318,146.46024114802876 -2021-07-30,225.9518625336191,145.99637718460662 -2021-08-02,228.09215135856905,147.39038385392448 -2021-08-03,228.94902363324627,148.44814332058604 -2021-08-04,229.70263689630303,148.94312990508698 -2021-08-05,230.512872973567,149.7149752199467 -2021-08-06,230.4474642878172,150.50470499215646 -2021-08-09,231.01910640433601,150.42125497145295 -2021-08-10,231.17795980328768,150.57645842682928 -2021-08-11,231.81668711348127,151.41057054437383 -2021-08-12,233.20360546523048,151.951039061099 -2021-08-13,234.17614474084854,152.2506333674381 -2021-08-16,233.84057878548498,150.98622702739257 -2021-08-17,232.98232590124329,150.56828698700323 -2021-08-18,234.1656371647858,149.47034947781978 -2021-08-19,232.22238922740735,145.84470965569847 -2021-08-20,233.54757509064817,146.29112037231542 -2021-08-23,234.49280991904496,147.5493496213051 -2021-08-24,234.87815288775033,147.1345035165755 -2021-08-25,234.68101245358085,147.40319080710825 -2021-08-26,233.72872448003952,147.17247160505474 -2021-08-27,235.23294168643716,147.52329372412902 -2021-08-30,236.76857736598416,147.6420706687242 -2021-08-31,236.13696864778578,147.48488364484126 -2021-09-01,238.65033322161582,149.21822067221157 -2021-09-02,239.267563776577,149.31514602244349 -2021-09-03,238.61425795130143,147.7014699212854 -2021-09-06,239.59681596021667,148.88285745117233 -2021-09-07,240.5143190266187,148.498034380632 -2021-09-08,239.64838605393882,147.23562238935668 -2021-09-09,239.04500009497076,147.58511853600535 -2021-09-10,239.69525393730999,147.12258054500882 -2021-09-13,238.66245191676666,147.41313021016842 -2021-09-14,241.3353542764023,146.88414267420143 -2021-09-15,240.843267403143,145.35303261212974 -2021-09-16,243.21034314120786,146.21340545185922 -2021-09-17,240.39771641700537,145.05652146118675 -2021-09-20,236.3629396199004,142.53124470756396 -2021-09-21,237.24794378395805,144.6710407945654 -2021-09-22,239.43766047337934,146.53155259189302 -2021-09-23,240.26758093009647,147.96617929454135 -2021-09-24,236.86747115363738,146.56378558012497 -2021-09-27,234.84190086938307,146.83866074197715 -2021-09-28,229.76950840679356,143.6503762150297 -2021-09-29,230.3923015479785,144.84920621145818 -2021-09-30,230.3923015479785,143.94864454894318 -2021-10-01,230.3923015479785,143.89742751647162 -2021-10-04,230.3923015479785,143.0136507244172 -2021-10-05,230.3923015479785,145.19097290908937 -2021-10-06,230.3923015479785,143.35497543123986 -2021-10-07,230.3923015479785,145.71886085816686 -2021-10-08,230.3923015479785,144.83133253437174 -2021-10-11,230.3923015479785,145.0642509102043 -2021-10-12,230.3923015479785,144.56903794016728 -2021-10-13,230.3923015479785,145.6568204410181 -2021-10-14,230.3923015479785,147.595931140419 -2021-10-15,230.3923015479785,148.53005176359156 -2021-10-18,230.3923015479785,147.32856982231186 -2021-10-19,230.3923015479785,147.25681638763902 -2021-10-20,230.3923015479785,148.04631977431274 -2021-10-21,230.3923015479785,147.61712513870128 -2021-10-22,230.3923015479785,148.66627117472828 -2021-10-25,230.3923015479785,148.206611514119 -2021-10-26,230.3923015479785,149.3908665941296 -2021-10-27,230.3923015479785,149.1040792409743 -2021-10-28,230.3923015479785,150.22343713397606 -2021-10-29,233.78509413077646,150.80010577594635 -2021-11-01,236.1715144320729,152.189918922715 -2021-11-02,239.07644278707636,152.93482435878153 -2021-11-03,241.91286850329172,153.4563088312671 -2021-11-04,243.98627757364443,154.27628802320226 -2021-11-05,244.77895319535705,155.44642095786705 -2021-11-08,246.4319336834153,155.59412134976196 -2021-11-09,244.13211824362327,155.50117391680683 -2021-11-10,242.42481366657657,155.5429043172904 -2021-11-11,244.6758389304361,155.86059868625202 -2021-11-12,246.46817078091462,156.5637845020986 -2021-11-15,247.48333976907296,157.38574726254032 -2021-11-16,247.9427875283943,157.91496118404342 -2021-11-17,249.07986309092277,158.0087925986156 -2021-11-18,249.5078897698098,157.6804904502492 -2021-11-19,249.84615900428022,157.02499652066956 -2021-11-22,249.57534665466073,156.86404718478232 -2021-11-23,244.20719850180552,155.5309813457237 -2021-11-24,243.87964422891716,155.47821195529048 -2021-11-25,243.8708820025966,156.22091821757795 -2021-11-26,233.78131447505524,148.79962303574132 -2021-11-29,236.5694446559383,149.60591129287562 -2021-11-30,236.5694446559383,148.38963882990555 -2021-12-01,236.5694446559383,151.93779011710674 -2021-12-02,236.5694446559383,150.03643190091267 -2021-12-03,236.5694446559383,149.3690149997663 -2021-12-06,236.5694446559383,151.5825480899472 -2021-12-07,236.5694446559383,155.98954141944347 -2021-12-08,236.5694446559383,154.8675315815905 -2021-12-09,236.5694446559383,154.72756063871307 -2021-12-10,236.5694446559383,154.3621743834845 -2021-12-13,236.5694446559383,153.28543087258333 -2021-12-14,236.5694446559383,152.2345168733222 -2021-12-15,236.5694446559383,152.94807330277382 -2021-12-16,236.5694446559383,154.65779077254678 -2021-12-17,236.5694446559383,152.92599532287448 -2021-12-20,236.5694446559383,151.67793186248102 -2021-12-21,236.5694446559383,153.7729143936028 -2021-12-22,236.5694446559383,155.68662679190854 -2021-12-23,236.5694446559383,156.8894347056138 -2021-12-24,236.5694446559383,156.4573725198787 -2021-12-27,236.5694446559383,157.64538991189363 -2021-12-28,236.5694446559383,158.54439921644695 -2021-12-29,236.5694446559383,158.11189503990332 -2021-12-30,236.5694446559383,158.37042732210344 -2021-12-31,237.0447820870748,157.9244478160314 -2022-01-03,239.08433087758655,159.3416428324018 -2022-01-04,239.88088296313003,161.5536343448846 -2022-01-05,238.97304921438126,162.85535117732837 -2022-01-06,235.95980026905656,160.05785120670458 -2022-01-07,238.5985031203921,159.3915338924477 -2022-01-10,230.15776877969094,157.10182745950866 -2022-01-11,232.092875242709,158.59451666202895 -2022-01-12,233.4642579456865,159.78253405404385 -2022-01-13,233.64240687578547,158.98662719077825 -2022-01-14,229.79839475223685,157.70301042095704 -2022-01-17,230.37209066644542,158.99766618072792 -2022-01-18,226.6105511403019,157.5005570701223 -2022-01-19,226.6658512124985,158.3649078271286 -2022-01-20,228.69425174770106,158.83252332229142 -2022-01-21,222.9041652374733,156.06018448696307 -2022-01-24,213.93461944406,149.86069204333498 -2022-01-25,214.03522798710765,150.9683425700425 -2022-01-26,217.5637781755459,154.14757167554689 -2022-01-27,218.62224867736774,155.07131090485075 -2022-01-28,214.77949631170935,153.79255603392338 -2022-01-31,214.77949631170935,154.52820122353796 -2022-02-01,214.77949631170935,156.74240269006347 -2022-02-02,214.77949631170935,157.090788469559 -2022-02-03,214.77949631170935,154.67015573492196 -2022-02-04,214.77949631170935,153.47242532538297 -2022-02-07,214.77949631170935,154.75008060942082 -2022-02-08,214.77949631170935,155.17309815397647 -2022-02-09,214.77949631170935,157.4354227173138 -2022-02-10,214.77949631170935,156.78787384202408 -2022-02-11,214.77949631170935,154.80196601823698 -2022-02-14,214.77949631170935,151.28273817833556 -2022-02-15,214.77949631170935,154.10364210128427 -2022-02-16,214.77949631170935,153.7726880080667 -2022-02-17,214.77949631170935,153.37174844341038 -2022-02-18,214.77949631170935,152.99222926257244 -2022-02-21,214.77949631170935,149.87283062017417 -2022-02-22,214.77949631170935,149.85649852078575 -2022-02-23,214.77949631170935,149.70349423918844 -2022-02-24,214.77949631170935,143.97160651045957 -2022-02-25,214.77949631170935,149.0800176925683 -2022-02-28,214.77949631170935,147.01351661793774 -2022-03-01,214.77949631170935,141.2215828208303 -2022-03-02,214.77949631170935,143.46315537669386 -2022-03-03,214.77949631170935,140.82152723779103 -2022-03-04,214.77949631170935,133.8292110862934 -2022-03-07,214.77949631170935,132.0764372436113 -2022-03-08,214.77949631170935,131.65011015812348 -2022-03-09,214.77949631170935,141.03038406521762 -2022-03-10,214.77949631170935,137.04244114326383 -2022-03-11,214.77949631170935,138.21367366481815 -2022-03-14,214.77949631170935,140.63540598634467 -2022-03-15,214.77949631170935,140.30556226028023 -2022-03-16,214.77949631170935,145.46386450243492 -2022-03-17,214.77949631170935,145.99108407516778 -2022-03-18,214.77949631170935,146.16153082330666 -2022-03-21,214.77949631170935,145.3245511556385 -2022-03-22,214.77949631170935,147.0263235711215 -2022-03-23,214.77949631170935,145.30468312978184 -2022-03-24,214.77949631170935,144.73815871588053 -2022-03-25,214.77949631170935,144.69201918757528 -2022-03-28,214.77949631170935,145.47423511604003 -2022-03-29,214.77949631170935,149.9571754027584 -2022-03-30,214.77949631170935,148.84068505988026 -2022-03-31,214.77949631170935,147.03647857945415 -2022-04-01,214.77949631170935,147.5760631145623 -2022-04-04,214.77949631170935,148.61505414225667 -2022-04-05,214.77949631170935,146.71943102630988 -2022-04-06,214.77949631170935,143.481039834044 -2022-04-07,214.77949631170935,142.6608450368364 -2022-04-08,214.77949631170935,144.571474279746 -2022-04-11,214.77949631170935,144.7390426974976 -2022-04-12,214.77949631170935,144.33281002340254 -2022-04-13,214.77949631170935,144.43723843711587 -2022-04-14,214.77949631170935,145.47953900574242 -2022-04-19,214.77949631170935,144.27496312880302 -2022-04-20,214.77949631170935,146.26463326459447 -2022-04-21,214.77949631170935,148.25584497808393 -2022-04-22,214.77949631170935,145.30445674424578 -2022-04-25,214.77949631170935,142.38927941591638 -2022-04-26,214.77949631170935,141.62074364198887 -2022-04-27,214.77949631170935,142.29831555146788 -2022-04-28,214.77949631170935,143.6865871205385 -2022-04-29,214.77949631170935,144.2524431580952 -2022-05-02,214.77949631170935,141.86448540249864 -2022-05-03,214.77949631170935,142.98097574537678 -2022-05-04,214.77949631170935,141.2036983634802 -2022-05-05,214.77949631170935,140.6014050348787 -2022-05-06,214.77949631170935,138.17194326433466 -2022-05-09,214.77949631170935,134.36702765816744 -2022-05-10,214.77949631170935,135.04901947573174 -2022-05-11,214.77949631170935,138.42297248305334 -2022-05-12,214.77949631170935,137.0216783555265 -2022-05-13,214.77949631170935,140.4751250268021 -2022-05-16,214.77949631170935,140.14593889681862 -2022-05-17,214.77949631170935,141.9656042752797 -2022-05-18,214.77949631170935,140.260080328056 -2022-05-19,214.77949631170935,138.48876443194283 -2022-05-20,214.77949631170935,138.76540755702914 -2022-05-23,214.77949631170935,140.38813907963032 -2022-05-24,214.77949631170935,138.05670224620772 -2022-05-25,214.77949631170935,139.0612503316275 -2022-05-26,214.77949631170935,141.53265810792752 -2022-05-27,214.77949631170935,143.8545975290985 -2022-05-30,214.77949631170935,144.88431753007734 -2022-05-31,214.65646918184197,142.81803206071922 -2022-06-01,211.96503927372208,141.71612741452262 -2022-06-02,211.9449799526587,143.51658236320802 -2022-06-03,212.24166556626372,143.18231872905827 -2022-06-06,217.31774024101622,144.58382846185756 -2022-06-07,216.18494101179405,143.51459879470144 -2022-06-08,217.17913892345823,142.3727209309918 -2022-06-09,215.04749579583313,140.38195120831085 -2022-06-10,206.6448343357504,136.6015391413581 -2022-06-13,199.40749602723727,132.96065602647425 -2022-06-14,201.17244402544281,131.36044447458093 -2022-06-15,203.0760833561221,133.1330863431197 -2022-06-16,197.82246977694896,129.95629357719403 -2022-06-17,194.09866898780422,129.87702629877614 -2022-06-20,198.70543691835002,130.70362457257565 -2022-06-21,201.5083796061933,131.68764703605777 -2022-06-22,197.73382890323487,130.62723562454505 -2022-06-23,190.75243961244394,129.8920432060026 -2022-06-24,195.22921854824318,134.08730137768498 -2022-06-27,195.8646066625701,133.5123899186852 -2022-06-28,198.2458167602398,134.3670276581674 -2022-06-29,196.44447346786743,133.1628937720365 -2022-06-30,196.44447346786743,130.76478100810738 -2022-07-01,196.44447346786743,130.94582475538738 -2022-07-04,196.44447346786743,131.46664085152835 -2022-07-05,196.44447346786743,127.94100953503502 -2022-07-06,196.44447346786743,130.53340420997287 -2022-07-07,196.44447346786743,132.61580617344694 -2022-07-08,196.44447346786743,133.1993202828177 -2022-07-11,196.44447346786743,132.386186558283 -2022-07-12,196.44447346786743,133.44373041967208 -2022-07-13,196.44447346786743,132.47318328571836 -2022-07-14,196.44447346786743,130.60030652601552 -2022-07-15,196.44447346786743,133.2626866723921 -2022-07-18,196.44447346786743,134.49706997824833 -2022-07-19,196.44447346786743,136.9104152546764 -2022-07-20,196.44447346786743,136.54480261391174 -2022-07-21,196.44447346786743,136.90797891509766 -2022-07-22,196.44447346786743,137.25482311689512 -2022-07-25,196.44447346786743,137.7124992089978 -2022-07-26,196.44447346786743,137.13627255783604 -2022-07-27,196.44447346786743,138.1626722376191 -2022-07-28,196.44447346786743,139.9569500952487 -2022-07-29,199.50166344720168,142.3698533808682 -2022-08-01,199.7920833169525,142.1128626763661 -2022-08-02,199.1436720702792,141.51543124665844 -2022-08-03,201.865775023401,142.8900118809282 -2022-08-04,202.55833503740118,143.80249651500995 -2022-08-05,198.68492334170705,142.8964153575201 -2022-08-08,200.1927865929386,144.04645388079214 -2022-08-09,196.90051464066744,143.28608954669065 -2022-08-10,201.01524452153885,144.0243759008928 -2022-08-11,202.29492062274417,144.49309098294515 -2022-08-12,202.5267567612321,144.6959863245884 -2022-08-15,204.3151034214832,145.05122835174797 -2022-08-16,204.91103157214448,145.55085044960666 -2022-08-17,201.92288109695085,144.13211385553825 -2022-08-18,203.72224868430754,144.77414323585313 -2022-08-19,201.27447686340162,143.4148058943459 -2022-08-22,195.81573184356375,140.82969867761702 -2022-08-23,195.1460385637075,140.46055011038413 -2022-08-24,196.5960796861166,141.00675372735662 -2022-08-25,197.1025994768822,140.89195470003824 -2022-08-26,192.314287547076,138.52298098868133 -2022-08-29,189.45824301723883,137.3753680247244 -2022-08-30,189.5768548695532,137.1091170737704 -2022-08-31,189.5768548695532,135.22983683747566 -2022-09-01,189.5768548695532,133.22537617999384 -2022-09-02,189.5768548695532,136.16615663442724 -2022-09-05,189.5768548695532,134.5259934255481 -2022-09-06,189.5768548695532,134.77745385481174 -2022-09-07,189.5768548695532,134.80637730211149 -2022-09-08,189.5768548695532,135.24749490928966 -2022-09-09,189.5768548695532,137.15569859288416 -2022-09-12,189.5768548695532,139.8328692609511 -2022-09-13,189.5768548695532,137.8922169838522 -2022-09-14,189.5768548695532,137.37824635511166 -2022-09-15,189.5768548695532,135.9526642936428 -2022-09-16,189.5768548695532,134.1745029301292 -2022-09-19,189.5768548695532,133.82765872833173 -2022-09-20,189.5768548695532,132.0146232119986 -2022-09-21,189.5768548695532,133.15958423110436 -2022-09-22,189.5768548695532,130.6685240342201 -2022-09-23,189.5768548695532,127.68601317930316 -2022-09-26,189.5768548695532,127.37647946990393 -2022-09-27,189.5768548695532,127.03271842350256 -2022-09-28,189.5768548695532,127.27976972494449 -2022-09-29,189.5768548695532,125.33382433840681 -2022-09-30,189.5768548695532,127.22082324345543 -2022-10-03,189.5768548695532,127.92312507768494 -2022-10-04,189.5768548695532,133.344153124589 -2022-10-05,189.5768548695532,132.14686470585858 -2022-10-06,189.5768548695532,131.06415970917405 -2022-10-07,189.5768548695532,129.53018209697873 -2022-10-10,189.5768548695532,128.94754118896145 -2022-10-11,189.5768548695532,128.78527666091222 -2022-10-12,189.5768548695532,128.46006844820553 -2022-10-13,189.5768548695532,129.80063735074557 -2022-10-14,189.5768548695532,130.96480879962704 -2022-10-17,189.5768548695532,133.36557350840738 -2022-10-18,189.5768548695532,133.94710404927153 -2022-10-19,189.5768548695532,133.36689948083296 -2022-10-20,189.5768548695532,134.38645369321557 -2022-10-21,189.5768548695532,133.2492221231273 -2022-10-24,189.5768548695532,135.36803981711896 -2022-10-25,189.5768548695532,137.9995129476892 -2022-10-26,189.5768548695532,138.56824731563316 -2022-10-27,189.5768548695532,137.85556408753496 -2022-10-28,189.5768548695532,138.4962674954242 -2022-10-31,189.70558346351788,138.35762252497236 -2022-11-01,192.20957127834833,139.714976297973 -2022-11-02,190.45619377516692,138.58082788328085 -2022-11-03,191.31929555459956,137.83900560261043 -2022-11-04,194.30129087875386,141.6620320516638 -2022-11-07,194.34119448642363,141.6657835834045 -2022-11-08,193.57651360120556,142.2153075215728 -2022-11-09,193.36825522036824,141.97399132037816 -2022-11-10,195.1792246888435,144.7615626682054 -2022-11-11,194.39578433890176,145.59589039102244 -2022-11-14,195.04882432785138,145.91712068645234 -2022-11-15,197.4263201749824,146.6344394279083 -2022-11-16,197.6491960217052,145.8740750938068 -2022-11-17,196.67311256416556,145.18744776288472 -2022-11-18,198.37557579209636,146.696253459521 -2022-11-21,197.48898887474485,146.47525805525518 -2022-11-22,200.0644114114771,146.9848087759104 -2022-11-23,200.20673292975073,147.46081131617174 -2022-11-24,200.97913961389946,148.08407225751947 -2022-11-25,201.95967908145738,148.1979980834844 -2022-11-28,200.03977999233388,147.1541559371598 -2022-11-29,201.08232724438577,147.23739035259084 -2022-11-30,204.1856866053384,148.7735671385652 -2022-12-01,202.91489032733068,149.11401864403442 -2022-12-02,202.23017828331913,148.8552599762982 -2022-12-05,201.15814373690688,147.8553474042362 -2022-12-06,201.10673922654124,147.65289405340147 -2022-12-07,198.7760156022426,147.05236868803408 -2022-12-08,198.33101857564014,146.7591778582869 -2022-12-09,198.6982676319736,147.42880471347596 -2022-12-12,198.54989538553426,146.8307049074237 -2022-12-13,200.57198156502352,148.91553243021292 -2022-12-14,200.15387538049612,148.60224718907298 -2022-12-15,194.7060913785881,144.00958537920258 -2022-12-16,193.12713694874162,142.46103285058933 -2022-12-19,194.24592611716426,142.91716736499396 -2022-12-20,192.24034171676647,142.41246776296896 -2022-12-21,196.53172314602992,145.2784116273334 -2022-12-22,194.8833672594742,143.9036153877912 -2022-12-23,194.64529326963586,143.61504929113815 -2022-12-27,196.178605304848,144.62534325706886 -2022-12-28,194.42383456622238,143.7384725293547 -2022-12-29,195.63551684701258,145.12894327220434 -2022-12-30,195.63551684701258,142.92753797859902 -2023-01-02,195.63551684701258,145.59478002386945 -2023-01-03,195.63551684701258,146.2421132938867 -2023-01-04,195.63551684701258,149.6098892101525 -2023-01-05,195.63551684701258,149.2802610893605 -2023-01-06,195.63551684701258,151.47592050245493 -2023-01-09,195.63551684701258,152.50055221900385 -2023-01-10,195.63551684701258,151.65673786419887 -2023-01-11,195.63551684701258,152.8721263455519 -2023-01-12,195.63551684701258,154.00892670509526 -2023-01-13,195.63551684701258,155.06469182298662 -2023-01-16,195.63551684701258,155.50205789842408 -2023-01-17,195.63551684701258,156.24939967406934 -2023-01-18,195.63551684701258,156.38694505763166 -2023-01-19,195.63551684701258,153.48324871006045 -2023-01-20,195.63551684701258,154.45733177048243 -2023-01-23,195.63551684701258,155.25279664293953 -2023-01-24,195.63551684701258,155.6603552894602 -2023-01-25,195.63551684701258,155.51463846607186 -2023-01-26,195.63551684701258,156.66512976041608 -2023-01-27,195.63551684701258,156.69205885894564 -2023-01-30,195.63551684701258,156.3564692523703 -2023-01-31,196.61179146161055,156.36552467381335 -2023-02-01,197.71118476711993,156.24828930691626 -2023-02-02,202.26745864413448,158.21676544442542 -2023-02-03,204.2027980269401,159.7107806193713 -2023-02-06,200.24474379593394,157.57275249560394 -2023-02-07,200.77534991106765,157.4678820910821 -2023-02-08,198.0660004397306,157.19146535153186 -2023-02-09,200.07338077898834,158.7044645707174 -2023-02-10,196.34789166275388,157.4100351964826 -2023-02-13,198.43349066781008,159.15110167287042 -2023-02-14,197.79407807007541,159.26635347126094 -2023-02-15,200.9249222430316,161.1882373093927 -2023-02-16,205.32585718296292,162.6299358649775 -2023-02-17,204.41671160170515,162.2228192092654 -2023-02-20,203.09928522258525,161.95544711089462 -2023-02-21,201.37911253695827,161.3602256352296 -2023-02-22,199.13930046003026,161.152910385501 -2023-02-23,200.33844073000327,161.55407633569337 -2023-02-24,196.41716333094874,158.68040302231142 -2023-02-27,199.46206648211134,161.07100194249554 -2023-02-28,199.5657483200982,160.46121633067622 -2023-03-01,199.20457725249628,159.71762608677167 -2023-03-02,198.34625494152502,160.8208674856575 -2023-03-03,199.72922928564194,162.23164824517232 -2023-03-06,200.7368112336793,162.7855813111623 -2023-03-07,199.02228401172715,162.03625596701048 -2023-03-08,200.80780949963693,161.71589887293402 -2023-03-09,200.5797235990375,161.51984899869117 -2023-03-10,199.20607126544203,159.41780539489648 -2023-03-13,193.58472111310687,154.79975606419453 -2023-03-14,195.8014618656879,157.67143502880626 -2023-03-15,190.50437159509522,152.02256611023597 -2023-03-16,192.49166910757594,155.11370968167907 -2023-03-17,189.88310952654638,152.89883983880895 -2023-03-20,191.43611358008093,154.83596696970324 -2023-03-21,194.64569534205967,157.03868745547052 -2023-03-22,194.84659875686586,157.44072660701636 -2023-03-23,194.34445372403354,157.62021799633467 -2023-03-24,189.22297570782152,154.87923894788483 -2023-03-27,191.75142899618172,156.27390321328372 -2023-03-28,190.94279484767233,156.49622458997513 -2023-03-29,194.42291985201453,158.67422593125553 -2023-03-30,196.7183329942963,160.36053944870355 -2023-03-31,198.3884234077303,161.66358225357288 -2023-04-03,199.38804347174025,162.1839563589053 -2023-04-04,200.237950688673,162.16187837900597 -2023-04-05,203.48354975226468,161.52912002540663 -2023-04-06,203.96593909846015,161.71568326766146 -2023-04-11,204.97064750821067,163.16244854714895 -2023-04-12,204.79738515167176,163.3094913429629 -2023-04-13,205.42764844903272,165.16161609519202 -2023-04-14,204.0985335807177,166.01779541237227 -2023-04-17,205.70501601338157,165.54467120249822 -2023-04-18,206.41289037770258,166.32732912177153 -2023-04-19,207.1037897159229,166.67638327761168 -2023-04-20,207.91797437433604,166.43948698450234 -2023-04-21,210.04577327695145,167.28485369726903 -2023-04-24,207.99381857560707,167.2155258219113 -2023-04-25,208.60164368640665,166.2827311711644 -2023-04-26,209.703007460452,164.8487728448607 -2023-04-27,210.8930150166095,165.22806564016258 -2023-04-28,213.70912984334677,165.39718641587584 -2023-05-02,211.02814946040317,163.0061455048832 -2023-05-03,212.56561792873754,163.4616116429432 -2023-05-04,212.50925498414557,162.06937293685945 -2023-05-05,213.11181278329525,164.10408301406665 -2023-05-08,214.56659159233433,164.2802648624528 -2023-05-09,214.92723161818486,163.3145688471293 -2023-05-10,213.62219549864403,162.5204299470978 -2023-05-11,213.35551410313963,162.9747857180047 -2023-05-12,213.78257377640668,163.70491141264446 -2023-05-15,213.70222645997413,163.77909040663243 -2023-05-16,211.3541170420302,163.5097347397551 -2023-05-17,210.46928633932387,163.36468629271135 -2023-05-18,209.77492039198538,164.4122907510403 -2023-05-19,210.68433628903043,165.40734142420848 -2023-05-22,210.3710392816382,165.10266961370309 -2023-05-23,209.9145186841854,162.90701020060865 -2023-05-24,208.03262763132676,160.14174321821682 -2023-05-25,205.7174897558435,159.60767817808352 -2023-05-26,206.02156842367424,161.59271280051718 -2023-05-29,206.41503044345606,161.25337166220112 -2023-05-30,205.4869774479603,159.17671557923794 -2023-05-31,205.4869774479603,156.72496022352212 -2023-06-01,205.4869774479603,157.58003995381287 -2023-06-02,205.4869774479603,160.52214638067187 -2023-06-05,205.4869774479603,158.9815496866122 -2023-06-06,205.4869774479603,159.16015709431346 -2023-06-07,205.4869774479603,159.02305370155966 -2023-06-08,205.4869774479603,159.45048037393698 -2023-06-09,205.4869774479603,159.25156294957048 -2023-06-12,205.4869774479603,160.07308371920368 -2023-06-13,205.4869774479603,160.96613153797367 -2023-06-14,205.4869774479603,161.79913328836506 -2023-06-15,205.4869774479603,160.9685678775524 -2023-06-16,205.4869774479603,163.12646402717644 -2023-06-19,205.4869774479603,161.47944457063323 -2023-06-20,205.4869774479603,161.0405369174977 -2023-06-21,205.4869774479603,160.3075544529979 -2023-06-22,205.4869774479603,159.03386630597322 -2023-06-23,205.4869774479603,158.1538410456595 -2023-06-26,205.4869774479603,158.6159370458475 -2023-06-27,205.4869774479603,159.3054319268932 -2023-06-28,205.4869774479603,160.86722261923512 -2023-06-29,205.4869774479603,161.45030551806093 -2023-06-30,208.229781301112,163.37837722751212 -2023-07-03,209.66556411612063,163.0834184345308 -2023-07-04,209.90752108384723,162.7131702804084 -2023-07-05,208.7052434060445,161.4079175214964 -2023-07-06,202.86584903009302,156.3626571236896 -2023-07-07,203.7961467869229,157.01594109922658 -2023-07-10,202.82619219752092,157.71824293345608 -2023-07-11,204.22792936698735,159.4032304784785 -2023-07-12,205.66840335132474,161.8980422071035 -2023-07-13,208.34862385423878,162.71029195002114 -2023-07-14,207.1971949688409,162.81494674927052 -2023-07-17,206.04530457911116,160.98512636247682 -2023-07-18,205.8008229090857,161.5927128005171 -2023-07-19,206.19992402317183,161.7640327500094 -2023-07-20,208.10221185641709,163.04389798808987 -2023-07-21,209.1818789810162,164.10054708759827 -2023-07-24,210.45547967213872,163.980002179769 -2023-07-25,210.99900535655414,163.71816035663667 -2023-07-26,210.0581555521626,161.50196454134098 -2023-07-27,210.93489613954782,164.8174238382457 -2023-07-28,210.5851604622207,165.06535912130468 -2023-07-31,209.42968814198147,165.53583138632754 -2023-08-01,207.3824186734413,163.5112870977166 -2023-08-02,204.68217825031292,161.45273107737597 -2023-08-03,206.79695787958534,160.29783065521008 -2023-08-04,208.09364310326114,161.50196454134095 -2023-08-07,208.17606538495428,161.6055089734372 -2023-08-08,206.28193710175972,160.4952172821421 -2023-08-09,207.08085613523156,161.6558528045553 -2023-08-10,208.68979513439731,164.1193155265654 -2023-08-11,206.58978757664576,162.05656598367554 -2023-08-14,207.188906760295,162.24753835375208 -2023-08-15,205.63980407929554,160.45613882650974 -2023-08-16,204.48051697285158,160.29165356415425 -2023-08-17,204.1711508586644,158.77909633577727 -2023-08-18,202.85975048949857,158.16907355815826 -2023-08-21,203.4608948092685,158.91862528784617 -2023-08-22,205.04869467696665,159.8640005062408 -2023-08-23,205.48378950015382,159.99073328538955 -2023-08-24,205.4401733241392,159.28070200214253 -2023-08-25,205.4155682152826,159.61496563629228 -2023-08-28,207.5597533086299,161.71479928604433 -2023-08-29,206.2325425241493,162.79044321005594 -2023-08-30,206.53227403802524,162.5910730146173 -2023-08-31,206.53227403802524,161.53795984157713 -2023-09-01,206.53227403802524,161.09794182128846 -2023-09-04,206.53227403802524,160.71687028248886 -2023-09-05,206.53227403802524,160.16956707862684 -2023-09-06,206.53227403802524,158.83097096432974 -2023-09-07,206.53227403802524,158.8753533096645 -2023-09-08,206.53227403802524,159.86157494692566 -2023-09-11,206.53227403802524,160.68949919315074 -2023-09-12,206.53227403802524,160.12893626503276 -2023-09-13,206.53227403802524,159.45975140065224 -2023-09-14,206.53227403802524,161.36066762603778 -2023-09-15,206.53227403802524,162.9094357599235 -2023-09-18,206.53227403802524,160.6424756832284 -2023-09-19,206.53227403802524,160.7745015718159 -2023-09-20,206.53227403802524,161.84903512867442 -2023-09-21,206.53227403802524,159.2683370397672 -2023-09-22,206.53227403802524,158.62630765945235 -2023-09-25,206.53227403802524,157.28087685801844 -2023-09-26,206.53227403802524,156.18007179871137 -2023-09-27,206.53227403802524,156.1308383347464 -2023-09-28,206.53227403802524,157.11220885337733 -2023-09-29,206.53227403802524,157.52771255418793 -2023-10-02,206.53227403802524,156.05069785497508 -2023-10-03,206.53227403802524,154.48072494254347 -2023-10-04,206.53227403802524,154.4736638698706 -2023-10-05,206.53227403802524,154.50722283052812 -2023-10-06,206.53227403802524,155.8738476302443 -2023-10-09,206.53227403802524,155.01832590914503 -2023-10-10,206.53227403802524,158.13198945129602 -2023-10-11,206.53227403802524,157.44271017552276 -2023-10-12,206.53227403802524,156.85366579091357 -2023-10-13,206.53227403802524,154.62378982108063 -2023-10-16,206.53227403802524,155.03576837568662 -2023-10-17,206.53227403802524,155.2015796104677 -2023-10-18,206.53227403802524,153.79499237350208 -2023-10-19,206.53227403802524,152.80987032313044 -2023-10-20,206.53227403802524,150.48837289276798 -2023-10-23,206.53227403802524,151.24454370432022 -2023-10-24,206.53227403802524,152.19786397700483 -2023-10-25,206.53227403802524,152.67077258160643 -2023-10-26,206.53227403802524,152.0943195449086 -2023-10-27,206.53227403802524,150.02826046108655 -2023-10-30,206.53227403802524,150.6837543906662 -2023-10-31,206.53227403802524,152.02124013781014 -2023-11-01,206.53227403802524,153.05846320227042 -2023-11-02,206.53227403802524,155.885770601811 -2023-11-03,206.53227403802524,155.5945633405704 -2023-11-06,206.53227403802524,154.84898952815928 -2023-11-07,206.53227403802524,154.24184508092753 -2023-11-08,206.53227403802524,155.30004653839762 -2023-11-09,206.53227403802524,157.05524594039485 -2023-11-10,206.53227403802524,155.54025237243914 -2023-11-13,206.53227403802524,156.4679695190198 -2023-11-14,206.53227403802524,158.64530248395556 -2023-11-15,206.53227403802524,159.17362164357797 -2023-11-16,206.53227403802524,158.26378895434743 -2023-11-17,206.53227403802524,159.71012302329 -2023-11-20,206.53227403802524,159.9975787527899 -2023-11-21,206.53227403802524,159.61165609536005 -2023-11-22,206.53227403802524,160.30225056329527 -2023-11-23,206.53227403802524,160.6819961296693 -2023-11-24,206.53227403802524,161.01028749777205 -2023-11-27,206.53227403802524,160.40734735335317 -2023-11-28,206.53227403802524,160.06822182030956 -2023-11-29,206.53227403802524,160.45481285408403 -2023-11-30,207.21508056580024,161.4070335398791 -2023-12-01,208.66571189409296,162.18814988145434 -2023-12-04,208.324355906149,161.88877118038772 -2023-12-05,209.25731180896938,163.0898219111225 -2023-12-06,210.63848934370733,164.17164292618997 -2023-12-07,210.65072326729586,164.00671567302595 -2023-12-08,211.52863382322798,166.17101529924184 -2023-12-11,211.79673707136095,166.7225228059167 -2023-12-12,211.79308565377738,166.54634095753053 -2023-12-13,210.10170396131747,166.27412852079317 -2023-12-14,210.4002584917413,167.25946617643726 -2023-12-15,210.47392793584413,167.72442972674892 -2023-12-18,207.9793285056214,167.10513592241438 -2023-12-19,207.5914662290966,167.23341027926116 -2023-12-20,208.585235697875,167.4268189889164 -2023-12-21,208.45009271208718,167.16121485377977 -2023-12-22,208.37943325023818,167.1042519407973 -2023-12-27,208.09953189500322,167.1704858804953 -2023-12-28,206.74559311583567,166.3611144679649 -2023-12-29,206.877260099802,166.53818029796815 -2024-01-02,207.1201773095972,166.2661726862396 -2024-01-03,202.26669493376772,163.63889307821862 -2024-01-04,203.1661650425997,164.49485679012642 -2024-01-05,202.11475274914935,163.83384336557194 -2024-01-08,203.03231176430634,164.4862541397555 -2024-01-09,202.6970293872018,163.9647696672699 -2024-01-10,202.1327299753185,163.95284669570316 -2024-01-11,200.30330848012977,163.1037284511958 -2024-01-12,202.12707086162987,164.81521388420288 -2024-01-15,200.60035561669977,163.63492594120547 -2024-01-16,200.17839709935853,163.33289529528764 -2024-01-17,197.55886841459227,161.58188941583967 -2024-01-18,199.6740423096781,163.40685868400314 -2024-01-19,198.80112308013324,162.75092276361497 -2024-01-22,201.072289942135,163.66958448875255 -2024-01-23,200.5423417607822,163.11299947791136 -2024-01-24,203.28316646839372,164.60547307515918 -2024-01-25,203.1881497870722,164.79446187672912 -2024-01-26,205.27318008591465,168.54639248719064 -2024-01-29,203.9784527999378,168.69365088827703 -2024-01-30,204.50737725394507,169.50303308107107 -2024-01-31,203.97700260231545,169.04557259424084 -2024-02-01,202.8826103421582,167.544269961086 -2024-02-02,204.09299979118782,167.62175849600612 -2024-02-05,204.06250825830995,167.57098345434312 -2024-02-06,205.54077364708624,168.65303085494665 -2024-02-07,204.6263992862548,168.0412401140935 -2024-02-08,205.3766586804359,169.24162246848368 -2024-02-09,204.68470524254988,168.84179327098053 -2024-02-12,204.81436342484668,169.77524551780846 -2024-02-13,203.9692834887849,168.35144219983738 -2024-02-14,205.67811159836705,169.50038113621991 -2024-02-15,208.55876204271354,170.95906938727413 -2024-02-16,210.6994386922072,171.50572577531878 -2024-02-19,210.96975674201389,171.5138864348812 -2024-02-20,212.40317327861263,172.1027152142179 -2024-02-21,212.75795640263874,172.47516254211936 -2024-02-22,216.51930824709896,174.67214792763937 -2024-02-23,217.61530059598093,175.88820478533697 -2024-02-26,216.57963900456542,175.07440268445762 -2024-02-27,215.938884035795,175.48461327582947 -2024-02-28,216.72806532648582,175.61686554995305 -2024-02-29,216.21382386533384,175.02164407428805 -2024-03-01,214.81447375358678,175.1704440530725 -2024-03-04,216.54643006967092,175.66146350056027 -2024-03-05,217.0326543507932,175.14063662415566 -2024-03-06,217.32556802433103,175.62459499897057 -2024-03-07,218.4061989997181,176.98194877197122 -2024-03-08,218.78522532324945,177.24223823714186 -2024-03-11,218.40558264433227,177.05943730689137 -2024-03-12,220.74971495584592,178.5552204450714 -2024-03-13,221.28185042672033,179.66132939408087 -2024-03-14,222.12499513162953,180.1876649851967 -2024-03-15,223.43583823334743,180.25235734719666 -2024-03-18,223.7658500570916,179.89447415544953 -2024-03-19,225.10368779819385,181.0626127413441 -2024-03-20,225.38189075271174,180.18744937992423 -2024-03-21,225.96993290207578,180.5916984855127 -2024-03-22,224.64749960007057,179.97792417615298 -2024-03-25,224.78906090093628,179.9708631034801 -2024-03-26,225.85934683756594,180.70274598109037 -2024-03-27,226.0431802037455,181.1456207712391 -2024-03-28,225.8891381455183,181.1676987511384 -2024-04-02,227.6910671752461,179.49507616849124 -2024-04-03,229.86101192600117,180.00684762345273 -2024-04-04,230.48700062024346,179.96975273632694 -2024-04-05,226.84776354102115,177.97744143594795 -2024-04-08,228.9766076399241,179.25773788457337 -2024-04-09,227.4438267949412,177.7094117414962 -2024-04-10,227.74418881055462,177.62573533525665 -2024-04-11,227.08030788369948,177.14797561202482 -2024-04-12,228.9853759014936,176.86294544184005 -2024-04-15,227.9641327504734,177.6197738494733 -2024-04-16,224.18097172091046,175.136001110798 -2024-04-17,224.87569427863187,176.21561217182278 -2024-04-18,226.39827114627641,177.13736783262007 -2024-04-19,226.0469455327816,177.11861017391652 -2024-04-22,227.83238303919987,177.51490344495141 -2024-04-23,230.30730676969472,178.95924316512378 -2024-04-24,228.50781877010817,178.6519194097672 -2024-04-25,226.7434182013506,176.99143540395923 -2024-04-26,228.99455100372595,178.57200531553195 -2024-04-29,230.3272033884988,178.062217429077 -2024-04-30,229.59705419418654,176.2911279184999 -2024-05-02,229.66148274286448,174.73948145422693 -2024-05-03,229.12813051813592,175.68706662666426 -2024-05-06,231.26202826826233,176.54966020070003 -2024-05-07,233.14049243958004,178.29470459436462 -2024-05-08,234.69898349240756,179.52510998294406 -2024-05-09,236.80040562922744,180.7667699667456 -2024-05-10,238.32795276765535,181.46199994803865 -2024-05-13,238.32278117343984,181.24432486496863 -2024-05-14,238.11667710166805,181.60904274385257 -2024-05-15,237.66761627180142,181.92233876525611 -2024-05-16,235.6375533322648,180.7853228004403 -2024-05-17,236.8111012694321,180.32190082782668 -2024-05-20,236.63881216193838,180.95045487861313 -2024-05-21,236.11260599886072,179.74698936882686 -2024-05-22,234.26741847617342,178.65743890474192 -2024-05-23,233.74627221513325,178.88308060262912 -2024-05-24,233.94997366346004,178.7205896890438 -2024-05-27,234.47179033061101,179.54895592607744 -2024-05-28,234.83284925609286,177.89994212076405 -2024-05-29,233.21749589262808,175.18942809731203 -2024-05-30,233.44889066022844,176.1493782321246 -2024-05-31,233.70292935007907,176.46642578526888 -2024-06-03,232.90914514870954,176.58012522569774 -2024-06-04,230.3392277512779,175.2527944868864 -2024-06-05,230.5004323246821,176.7688876417316 -2024-06-06,231.3995182486873,177.5096103355125 -2024-06-07,228.17056210181312,176.66357524640122 -2024-06-10,219.75812927041994,174.28313133454972 -2024-06-11,212.64399674333083,171.97002094928575 -2024-06-12,213.8808961130923,173.63669282641317 -2024-06-13,208.85473301908135,170.1775110548903 -2024-06-14,201.61805649450557,165.65704467050125 -2024-06-17,202.4460760635899,167.16496638552044 -2024-06-18,204.4779683612296,168.4284887439489 -2024-06-19,203.22622271899795,167.1347277460587 -2024-06-20,207.41675403089621,169.36768687128773 -2024-06-21,205.54194914939083,168.42341123978258 -2024-06-24,208.10159675651053,170.1525655248673 -2024-06-25,205.96495151872543,169.16810107057665 -2024-06-26,205.17656658401387,167.99465859497968 -2024-06-27,203.24278818890144,166.26308953084347 -2024-06-28,203.24278818890144,165.13004070304083 -2024-07-01,203.24278818890144,166.93447356900302 -2024-07-02,203.24278818890144,166.43021595778654 -2024-07-03,203.24278818890144,168.50091055496637 -2024-07-04,203.24278818890144,169.9072714063959 -2024-07-05,203.24278818890144,169.46218666220454 -2024-07-08,203.24278818890144,168.3986920952957 -2024-07-09,203.24278818890144,165.77604800063247 -2024-07-10,203.24278818890144,167.20868035451056 -2024-07-11,203.24278818890144,168.39162024235915 -2024-07-12,203.24278818890144,170.537377815144 -2024-07-15,203.24278818890144,168.51481709503963 -2024-07-16,203.24278818890144,167.35174523304772 -2024-07-17,203.24278818890144,167.14819229532347 -2024-07-18,203.24278818890144,167.49569409320193 -2024-07-19,203.24278818890144,166.34698154235548 -2024-07-22,203.24278818890144,168.2788047835474 -2024-07-23,203.24278818890144,167.7623978152281 -2024-07-24,203.24278818890144,165.8879794778272 -2024-07-25,203.24278818890144,163.97359870317686 -2024-07-26,203.24278818890144,165.97519181053502 -2024-07-29,203.24278818890144,164.3449464441888 -2024-07-30,203.24278818890144,165.03157377511084 -2024-07-31,203.24278818890144,166.28009000657647 -2024-08-01,203.24278818890144,162.72465126116631 -2024-08-02,203.24278818890144,160.1050903218992 -2024-08-05,203.24278818890144,157.83526269508047 -2024-08-06,203.24278818890144,157.4168806638826 -2024-08-07,203.24278818890144,160.4188175538477 -2024-08-08,203.24278818890144,160.009059733548 -2024-08-09,203.24278818890144,160.5005103915807 -2024-08-12,203.24278818890144,160.08014479187622 -2024-08-13,203.24278818890144,160.63651419744494 -2024-08-14,203.24278818890144,161.9057716561207 -2024-08-15,203.24278818890144,163.893016232597 -2024-08-16,203.24278818890144,164.47433116818868 -2024-08-19,203.24278818890144,165.23535309837118 -2024-08-20,203.24278818890144,165.26979604064576 -2024-08-21,203.24278818890144,166.1306216514474 -2024-08-22,203.24278818890144,166.117146321919 -2024-08-23,203.24278818890144,167.28573767888577 -2024-08-26,203.24278818890144,167.58003887578607 -2024-08-27,203.24278818890144,167.03713401948212 -2024-08-28,203.24278818890144,167.29964421895906 -2024-08-29,203.24278818890144,168.69674482393665 -2024-08-30,204.4805001519901,168.4759650249433 -2024-09-02,204.96382043597563,168.8175053370384 -2024-09-03,202.87700684193493,167.24290769151264 -2024-09-04,201.98189753372603,165.60626962883813 -2024-09-05,202.28665283899065,164.08266263024788 -2024-09-06,201.53599460156556,162.32392730178242 -2024-09-09,202.58841985462132,163.93473585281689 -2024-09-10,201.7935266785582,163.54373569122075 -2024-09-11,202.8054058792935,163.3070657836475 -2024-09-12,204.54943344345318,164.151322129261 -2024-09-13,205.049841718482,164.81763944351786 -2024-09-16,206.42522603182766,164.46858528767774 -2024-09-17,207.65350683216198,165.30710653304396 -2024-09-18,206.0338990389823,164.36835039651365 -2024-09-19,206.10843340704565,168.1328723548865 -2024-09-20,206.25700541266977,165.59058434526708 -2024-09-23,206.65519783597435,165.76324104744862 -2024-09-24,206.5327395260885,167.88117475982318 -2024-09-25,207.1329534996915,167.03360887327747 -2024-09-26,206.60188266525296,170.92970394916568 -2024-09-27,206.2933557197805,172.0269838622681 -2024-09-30,206.2933557197805,168.58193501635463 -2024-10-01,206.2933557197805,167.22016133526867 -2024-10-02,206.2933557197805,167.29787625572487 -2024-10-03,206.2933557197805,165.0942717883405 -2024-10-04,206.2933557197805,166.49799147518246 -2024-10-07,206.2933557197805,167.2632177081778 -2024-10-08,206.2933557197805,166.05554789557868 -2024-10-09,206.2933557197805,166.9115116074865 -2024-10-10,206.2933557197805,166.50306897934877 -2024-10-11,206.2933557197805,167.30450611785284 -2024-10-14,206.2933557197805,167.8381291671776 -2024-10-15,206.2933557197805,166.06990720672417 -2024-10-16,206.2933557197805,165.40822540582508 -2024-10-17,206.2933557197805,167.43343807078062 -2024-10-18,206.2933557197805,168.08076056053423 -2024-10-21,206.2933557197805,166.38473402556215 -2024-10-22,206.2933557197805,166.3597884955392 -2024-10-23,206.2933557197805,165.5292123044629 -2024-10-24,206.2933557197805,165.65726027577358 -2024-10-25,206.2933557197805,165.53053827688848 -2024-10-28,206.2933557197805,166.84196812685633 -2024-10-29,206.2933557197805,165.8301325832276 -2024-10-30,206.2933557197805,164.00317974655755 -2024-10-31,206.2933557197805,162.28132369994543 -2024-11-01,206.2933557197805,163.57817863349536 -2024-11-04,206.2933557197805,162.7524643413129 -2024-11-05,206.2933557197805,163.53490665531373 -2024-11-06,206.2933557197805,162.70609842747157 -2024-11-07,206.2933557197805,163.94224969656196 -2024-11-08,206.2933557197805,162.02300702301778 -2024-11-11,206.2933557197805,163.9705047675171 -2024-11-12,206.2933557197805,159.55711874169256 -2024-11-13,206.2933557197805,159.33302940176702 -2024-11-14,206.2933557197805,161.42976911585933 -2024-11-15,206.2933557197805,160.4987424283465 -2024-11-18,206.2933557197805,160.68861521153352 -2024-11-19,206.2933557197805,159.61584961790913 -2024-11-20,206.2933557197805,158.92723871848048 -2024-11-21,206.2933557197805,159.25553008658326 -2024-11-22,206.2933557197805,160.17595977495495 -2024-11-25,206.2933557197805,160.23028152334984 -2024-11-26,206.2933557197805,158.8402419910451 -2024-11-27,206.2933557197805,157.70366801703784 -2024-11-28,206.2933557197805,158.50333719230778 -2024-11-29,206.2933557197805,159.73661013101088 -2024-12-02,206.2933557197805,159.77591497217932 -2024-12-03,206.2933557197805,160.185015196398 -2024-12-04,206.2933557197805,161.24166429590642 -2024-12-05,206.2933557197805,161.84351563369938 -2024-12-06,206.2933557197805,163.97050476751707 -2024-12-09,206.2933557197805,165.14638358269278 -2024-12-10,206.2933557197805,163.26179945669566 -2024-12-11,206.2933557197805,163.89367382867792 -2024-12-12,206.2933557197805,163.83936286054663 -2024-12-13,206.2933557197805,163.58833364182792 -2024-12-16,206.2933557197805,162.42946608264884 -2024-12-17,206.2933557197805,162.6197808566444 -2024-12-18,206.2933557197805,163.03749451149767 -2024-12-19,206.2933557197805,161.0449568255826 -2024-12-20,206.2933557197805,160.60582278691098 -2024-12-23,206.2933557197805,160.55813090064404 -2024-12-24,206.2933557197805,160.78708213946342 -2024-12-27,206.2933557197805,162.39171359944206 -2024-12-30,206.2933557197805,161.4686319662192 -2024-12-31,208.04518432878982,162.95183453675148 -2025-01-02,205.63319088764808,163.23927948598774 -2025-01-03,201.33645410395957,160.77671152585833 -2025-01-06,206.87693453827188,164.38579286305517 -2025-01-07,207.24574731750673,165.34972091514453 -2025-01-08,204.6577629415202,164.53437723656714 -2025-01-09,204.0283186449018,165.37024653708218 -2025-01-10,202.11629013867258,164.06235261358262 -2025-01-13,197.11083909150162,163.5678080198902 -2025-01-14,197.7791137452908,163.89963531446122 -2025-01-15,203.22958633397803,165.0238443260932 -2025-01-16,211.59414053622825,168.55964143118277 -2025-01-17,212.88060210318136,170.2157055289054 -2025-01-20,210.26350039945208,170.7400575515146 -2025-01-21,212.96343106238393,171.5668822108502 -2025-01-22,214.27199678718796,173.0339575070029 -2025-01-23,212.52100833898305,174.25288191482414 -2025-01-24,214.51850312678542,175.025837596837 -2025-01-27,217.59165546989735,174.56131603733385 -2025-01-28,217.62111367539424,174.35797870488207 -2025-01-29,215.3230239763866,173.80845476671377 -2025-01-30,220.33592283606094,175.33537130623617 -2025-01-31,220.67260153669227,175.5236917314615 -2025-02-03,219.19294192088356,173.42076414604975 -2025-02-04,221.1020939810577,174.557338120057 -2025-02-05,221.2590925414334,174.2323562928864 -2025-02-06,229.37774505961931,176.7920759887838 -2025-02-07,232.16442409247617,176.0283913334865 -2025-02-10,231.20495241054394,176.76116897297746 -2025-02-11,233.7705061479429,177.26189065772567 -2025-02-12,236.57349455731534,177.55530787300896 -2025-02-13,239.4422014411746,180.2470534574938 -2025-02-14,239.30712366880903,180.56564258833615 -2025-02-17,239.91127185675288,180.79944494578575 -2025-02-18,241.20029281005247,181.18425723606248 -2025-02-19,239.4853694864415,179.0643399551813 -2025-02-20,239.00147086971666,179.3301596955904 -2025-02-21,240.06318016185983,180.03510269440747 -2025-02-24,240.66241396588148,178.63271976025473 -2025-02-25,243.97010131434527,177.7513577472518 -2025-02-26,245.80290261433623,179.80130033695787 -2025-02-27,246.43592718221342,178.8872741251781 -2025-02-28,246.45697676608782,179.08840150358722 -2025-03-03,248.1627258632479,181.0330316979629 -2025-03-04,247.86591810214108,177.68181426662161 -2025-03-05,250.88895127578758,180.45988820219725 -2025-03-06,254.111625695236,180.9879917565472 -2025-03-07,253.53213157611077,179.29085485442195 -2025-03-10,250.6589951509863,177.67475319394873 -2025-03-11,249.4698725965532,175.34133279201953 -2025-03-12,251.62276864482652,176.38009743417783 -2025-03-13,252.07780228460564,175.2596399542865 -2025-03-14,254.40576979548382,177.2481997229248 -2025-03-17,255.4870611308271,178.2571677164299 -2025-03-18,257.6694395755974,179.1533094708596 -2025-03-19,258.18921133865376,180.40955515134272 -2025-03-20,257.91515256092214,178.70358921331047 -2025-03-21,257.4177567417522,177.57209274346948 -2025-03-24,257.4446445383549,177.1168422106819 -2025-03-25,260.67503904345966,179.0212835822721 -2025-03-26,260.34151588415466,177.3011954988941 -2025-03-27,260.7264831583366,176.4054849550093 -2025-03-28,260.2389746251049,174.77105684637746 -2025-03-31,260.90226570460607,172.00313791913445 -2025-04-01,262.37291467450297,173.89411474145984 -2025-04-02,262.98585945954744,173.50709249714046 -2025-04-03,263.1624835469656,167.77012726424528 -2025-04-04,252.90923063799133,160.61620418077945 -2025-04-07,241.8951879906945,152.93681870755125 -2025-04-08,243.9956810360006,156.7629283120007 -2025-04-09,238.87267999803532,151.52161803995105 -2025-04-10,243.7962760206502,157.3281267534764 -2025-04-11,244.0090197657265,156.8596272766965 -2025-04-14,247.86189699180153,160.57579975272145 -2025-04-15,251.34472158409295,161.9508115975361 -2025-04-16,255.3635276701632,161.83093506605144 -2025-04-17,255.29419027290768,160.85706761090194 -2025-04-22,257.4983110275472,161.7536621364038 -2025-04-23,256.8340522441769,165.19539066112148 -2025-04-24,256.95954955717923,165.64622128582374 -2025-04-25,257.14891302240716,166.38539162164298 -2025-04-28,258.55852097255774,167.2133158678681 -2025-04-29,259.87972679411877,166.81834856925877 -2025-04-30,265.4159809841914,167.65731180543355 -2025-05-02,266.6771808328584,171.55650081698147 -2025-05-05,268.1917315130848,170.61708708437018 -2025-05-06,268.1489073051159,169.93244332195468 -2025-05-07,267.7267812456499,168.38521676576704 -2025-05-08,266.4915567917298,169.8776903630149 -2025-05-09,267.285939528916,170.96635684548278 -2025-05-12,264.92642437160634,173.31435216382988 -2025-05-13,263.24420600607726,173.83826219563056 -2025-05-14,265.28907845170346,173.02049295773807 -2025-05-15,269.68618645814894,173.3887575433539 -2025-05-16,271.62501558532506,174.12218199866223 -2025-05-19,273.2019721097882,174.05462208653861 -2025-05-20,278.5328141574956,175.35258738724167 -2025-05-21,278.9982608769246,174.6476443884246 -2025-05-22,279.7945938865307,173.630946945902 -2025-05-23,277.55889185019487,170.75992557737126 -2025-05-26,280.17657520537887,172.82929420212545 -2025-05-27,278.1040261939672,172.7997131587447 -2025-05-28,276.96338712720694,171.94551741007103 -2025-05-29,277.38676120687404,171.76050652577788 -2025-05-30,277.75493406364603,171.14607462033717 -2025-06-02,278.7994624926053,170.82175038924754 -2025-06-03,278.27804589586526,171.40990001197602 -2025-06-04,277.5207596476379,172.31134565610807 -2025-06-05,280.4170805910852,171.99342490161035 -2025-06-06,280.42875766311397,172.3157655641934 -2025-06-09,279.65734748475325,172.01992278959503 -2025-06-10,277.95432584867035,172.3038425926267 -2025-06-11,279.26554163954245,171.67616174319366 -2025-06-12,282.2973948645698,171.43793947765874 -2025-06-13,282.7331453362716,169.66221445372386 -2025-06-16,285.2116899874117,170.93302427036127 -2025-06-17,281.8554249273848,169.64123606071405 -2025-06-18,282.4933804396664,169.0316660541672 -2025-06-19,279.03325253512617,166.76492158274456 -2025-06-20,280.1594059271072,167.56436437247845 -2025-06-23,279.3177057279959,166.41431506894278 -2025-06-24,281.2015164388549,168.14567930807016 -2025-06-25,280.1768359949061,166.8689080056494 -2025-06-26,281.70956784816303,166.85013956668223 -2025-06-27,285.9241158041347,169.813881982632 -2025-06-30,286.1825973678971,169.24781033980287 -2025-07-01,283.57638581920975,169.17450454716837 -2025-07-02,286.63101287023625,170.8486794877772 -2025-07-03,286.45216839813816,171.2047947162902 -2025-07-04,287.0753227405889,169.9180947910729 -2025-07-07,287.1339421975789,170.51862015644028 -2025-07-08,287.11094918203213,171.4732664015505 -2025-07-09,287.6888542442425,173.9404806553013 -2025-07-10,288.6340396739003,174.4657166595276 -2025-07-11,288.925544308578,172.85490810849313 -2025-07-14,287.4019829092166,172.3886185857559 -2025-07-15,287.28018960246453,171.46222741160085 -2025-07-16,284.7205189325394,170.48814435117887 -2025-07-17,292.9193047648293,172.69395877260587 -2025-07-18,296.641677029969,172.70874929429624 -2025-07-21,298.0613794056107,172.16894915391566 -2025-07-22,299.4135602463418,170.98093176190076 -2025-07-23,295.9669627723161,173.32163962203893 -2025-07-24,291.0127936658462,172.61182394406438 -2025-07-25,292.2634187204428,172.97170148458173 -2025-07-28,291.7485846556669,172.22766924986865 -2025-07-29,293.2040849893543,173.4746331233726 -2025-07-30,293.77254918594343,173.57619398696227 -2025-07-31,302.4532780353391,171.58940218155809 -2025-08-01,296.7143928405207,166.60397224685738 -2025-08-04,299.49757029615574,168.49935819700445 -2025-08-05,297.9245916618181,168.25716879445636 -2025-08-06,297.09027320421126,168.566034127511 -2025-08-07,301.4985723769499,170.20620811665376 -2025-08-08,303.87550604244666,170.94979836055828 -2025-08-11,302.57709599086127,169.96777024584637 -2025-08-12,305.57028681912493,171.1798491862672 -2025-08-13,305.20044506151413,172.31797551823615 -2025-08-14,306.50256959856637,173.7612048712554 -2025-08-15,307.5812367939786,174.93377414549892 -2025-08-18,305.87551144229843,174.06389311325418 -2025-08-19,308.8959055536435,176.16196958003573 -2025-08-20,307.56416140779794,176.02839133348658 -2025-08-21,306.97155796591153,175.26140791752073 -2025-08-22,309.6029235070232,175.95465433030714 -2025-08-25,304.4018461890355,173.15848033210895 -2025-08-26,297.60855412470073,170.21703150133098 -2025-08-27,298.15720600465374,170.9703347627596 -2025-08-28,300.4578946073419,171.38252892263802 -2025-08-29,300.4578946073419,170.08654719044156 -2025-09-01,300.4578946073419,170.1748591100389 -2025-09-02,300.4578946073419,168.99037764449227 -2025-09-03,300.4578946073419,170.43560134628171 -2025-09-04,300.4578946073419,169.97659928175344 -2025-09-05,300.4578946073419,169.44363382850966 -2025-09-08,300.4578946073419,170.7696385948954 -2025-09-09,300.4578946073419,171.09087967058895 -2025-09-10,300.4578946073419,171.3542630714193 -2025-09-11,300.4578946073419,172.72751773326343 -2025-09-12,300.4578946073419,172.76549660200627 -2025-09-15,300.4578946073419,174.34826568735804 -2025-09-16,300.4578946073419,172.6105087519024 -2025-09-17,300.4578946073419,171.92078748532057 -2025-09-18,300.4578946073419,173.4139186786494 -2025-09-19,300.4578946073419,173.39139870794153 -2025-09-22,300.4578946073419,172.87300817111566 -2025-09-23,300.4578946073419,173.79829975838118 -2025-09-24,300.4578946073419,172.81428807516266 -2025-09-25,300.4578946073419,172.1071243420393 -2025-09-26,300.4578946073419,173.7687187150004 -2025-09-29,300.4578946073419,173.99369203654302 -2025-09-30,299.483446406745,174.32640331273112 -2025-10-01,298.9200032633395,175.89416627112004 -2025-10-02,303.72689149366846,177.87411260912376 -2025-10-03,307.7874655988316,178.4240785381006 -2025-10-06,304.53588719996225,176.00079385861238 -2025-10-07,308.85968639018773,176.06858015627205 -2025-10-08,316.0485405929942,177.9513855387714 -2025-10-09,313.43621103400096,177.53698142485032 -2025-10-10,308.71793780439316,174.81344484294206 -2025-10-13,307.999672932276,175.17242762157872 -2025-10-14,306.7090520748941,174.84921375764225 -2025-10-15,310.9584847187216,178.32384364693647 -2025-10-16,314.6929435551368,180.78752197421903 -2025-10-17,309.971366698141,180.4698276052574 -2025-10-20,318.5236088356493,181.1734554119125 -2025-10-21,320.08167111373916,182.3389528332195 -2025-10-22,315.4921468193696,181.1911134837265 -2025-10-23,326.20670791668385,181.6086115333073 -2025-10-24,322.77271738336634,181.6052912121115 -2025-10-27,321.67723403915227,181.90444352764206 -2025-10-28,322.25488185758104,181.40548980612795 -2025-10-29,320.8404623966697,181.05886120960292 -2025-10-30,316.9249354661431,180.09648551547522 -2025-10-31,316.5615783008039,179.29681634020528 -2025-11-03,320.22972917056495,179.04778147025678 -2025-11-04,317.8098557241028,178.11476043397374 -2025-11-05,318.1570188728805,178.26268721140474 -2025-11-06,306.01087635553455,175.84603239404453 -2025-11-07,305.6753907948833,175.52391811699758 -2025-11-10,308.6012924002873,177.8493826843732 -2025-11-11,310.0588660071402,180.0730815631503 -2025-11-12,315.1424639142615,181.94993624012997 -2025-11-13,313.6538421904357,181.75675391601078 -2025-11-14,310.951158573243,180.3790793460813 -2025-11-17,311.40835538776213,179.25156079351711 -2025-11-18,307.00256901015837,175.9158022602108 -2025-11-19,305.71948658552435,175.60317461515183 -2025-11-20,301.2497054683198,176.20589915429827 -2025-11-21,298.5586322667798,176.2407840873814 -2025-11-24,299.4653547033055,175.7334325405052 -2025-11-25,300.0862684816,177.193446763985 -2025-11-26,303.4270738314257,178.75282267727545 -2025-11-27,303.48186993853386,178.8199405985905 -2025-11-28,305.32924950261383,179.333027245714 -2025-12-01,304.1711869408382,178.76540324492316 -2025-12-02,305.05444986476704,178.27107425650323 -2025-12-03,305.87386126079724,178.55389447264534 -2025-12-04,307.81557547915287,179.31801033848754 -2025-12-05,304.0357737200266,179.1570717828639 -2025-12-08,306.4462971142379,179.01775843606748 -2025-12-09,306.8927650136708,177.78314874467517 -2025-12-10,304.7707728172122,177.12478726497187 -2025-12-11,305.84891221075486,178.51724157632808 -2025-12-12,305.5566891831404,178.13883276264326 -2025-12-15,306.98557403435757,179.38093473725337 -2025-12-16,305.01462453456236,178.96764099048545 -2025-12-17,308.7306588531321,178.52364505292002 -2025-12-18,311.6812019475309,179.9496691051974 -2025-12-19,313.8629229450637,179.9660012045858 -2025-12-22,312.93286050087414,179.2968163402053 -2025-12-23,313.61692536113145,178.91663956328637 -2025-12-24,312.56609498869256,178.910678077503 -2025-12-29,313.858228996954,179.0970149342218 -2025-12-30,316.8240082229015,180.33624935870827 -2025-12-31,315.8727514176762,179.92449718963837 -2026-01-02,321.1463854006014,180.93368078841593 -2026-01-05,323.17364954529745,181.2933319433972 -2026-01-06,323.6677416811172,181.86580706281825 -2026-01-07,326.59745592996853,181.7883185278981 -2026-01-08,328.4012826402956,181.99915892383132 -2026-01-09,326.47047246359466,184.61805148675384 -2026-01-12,327.26235603396833,184.54453008884687 -2026-01-13,323.99501744544335,184.28931812784253 -2026-01-14,326.45030318651004,183.93098216502324 -2026-01-15,328.273563532057,183.536898848031 -2026-01-16,326.3141017780009,182.3407207964537 -2026-01-19,325.7539300371462,179.09701493422182 -2026-01-20,322.57222225698916,178.00548090163028 -2026-01-21,321.39828767195957,178.15097133948254 -2026-01-22,326.6212051067405,179.9110326403736 -2026-01-23,324.97372408702086,179.7820899071822 -2026-01-26,328.1776776047875,179.51936410243283 -2026-01-27,331.70389546601666,179.99779220200924 -2026-01-28,330.65055493808154,178.09600277527025 -2026-01-29,329.2960427000232,178.1993208218304 -2026-01-30,332.4150753054988,179.41736124803458 -2026-02-02,334.236897044799,180.6237050882081 -2026-02-03,338.6565457194315,180.5868365866184 -2026-02-04,344.26382815036635,182.41180585478185 -2026-02-05,340.10668522722847,181.88214994247025 -2026-02-06,340.92685940094566,182.6696697606374 -2026-02-09,344.76346323304966,183.76121457349254 -2026-02-10,342.5555107581163,183.86276465681857 -2026-02-11,349.6680062714303,183.5395507928821 -2026-02-12,348.75243761018993,184.14270654257342 -2026-02-13,344.136196811241,183.5064338230331 -2026-02-16,346.88648458307,183.6115198328274 -2026-02-17,349.1704847583783,184.60414494668046 -2026-02-18,351.98190322252003,186.09596094784732 -2026-02-19,358.2430487487543,185.42810205589242 -2026-02-20,355.5423087338933,188.00482222752282 -2026-02-23,357.95513735553135,187.60034673639828 -2026-02-24,361.6983688303442,188.08694627580073 -2026-02-25,366.7916390405288,188.96698231637805 -2026-02-26,372.2000093607667,190.33271235421353 -2026-02-27,371.4231199540494,189.44562602122693 -2026-03-02,369.43891520741334,185.32963512796243 -2026-03-03,357.8821573134067,178.91641317775026 -2026-03-04,357.1065131632696,180.32697833199265 -2026-03-05,353.5022662597259,177.6350063619717 -2026-03-06,352.2407190821299,176.48011672006945 -2026-03-09,350.94703843123966,174.755155957534 -2026-03-10,356.91229309462017,177.8902291032397 -2026-03-11,357.60854111921884,177.54692082791047 -2026-03-12,359.3615090464977,176.2803045338223 -2026-03-13,363.0016999030818,174.67059556967735 -2026-03-16,364.52210078865096,175.21019088504912 -2026-03-17,369.689821729565,176.0606351019821 -2026-03-18,368.29627912139244,175.95884785285634 -2026-03-19,365.7122781194571,172.38199950389145 -2026-03-20,358.72489421736424,169.24140686321093 -2026-03-23,357.8146292483316,170.5788926103549 -2026-03-24,362.4117638577299,170.9701083772235 -2026-03-25,366.14875062286075,173.2359688670291 -2026-03-26,366.97232254324524,171.53067130534146 -2026-03-27,363.8304794396593,170.043501597796 -2026-03-30,370.7371237159003,171.59999918069917 -2026-03-31,370.7371237159003,172.58224290068355 -2026-04-01,370.7371237159003,176.21031906238363 -2026-04-02,370.7371237159003,175.79348938914745 -2026-04-07,370.7371237159003,174.6090079236008 -2026-04-08,370.7371237159003,182.44955833798872 diff --git a/rebalance_history.csv b/rebalance_history.csv deleted file mode 100644 index 4763dcc..0000000 --- a/rebalance_history.csv +++ /dev/null @@ -1,120 +0,0 @@ -Date,N_Stocks,Allocation -2016-05-31,15,"OrderedDict({'ATO.PA': 0.02, 'BNP.PA': 0.07642, 'CAP.PA': 0.02, 'CS.PA': 0.02, 'DG.PA': 0.09095, 'EL.PA': 0.02, 'ERF.PA': 0.20167, 'GLE.PA': 0.25, 'HO.PA': 0.02, 'OR.PA': 0.02, 'SAF.PA': 0.18095, 'STLAP.PA': 0.02, 'SU.PA': 0.02, 'VIV.PA': 0.02, 'WLN.PA': 0.02})" -2016-06-30,0,{} -2016-07-29,13,"OrderedDict({'ATO.PA': 0.02, 'DSY.PA': 0.02, 'HO.PA': 0.1175, 'KER.PA': 0.22414, 'MC.PA': 0.02, 'MT.AS': 0.25, 'PUB.PA': 0.02, 'RI.PA': 0.02, 'RMS.PA': 0.02, 'STLAP.PA': 0.02, 'STMPA.PA': 0.22836, 'SU.PA': 0.02, 'TEP.PA': 0.02})" -2016-08-31,4,"OrderedDict({'ALO.PA': 0.46, 'LR.PA': 0.5, 'STLAP.PA': 0.02, 'TEP.PA': 0.02})" -2016-09-30,6,"OrderedDict({'ATO.PA': 0.02, 'ERF.PA': 0.33333, 'FR.PA': 0.27333, 'STLAP.PA': 0.02, 'STMPA.PA': 0.33333, 'TEP.PA': 0.02})" -2016-10-31,8,"OrderedDict({'BNP.PA': 0.02108, 'GLE.PA': 0.25, 'HO.PA': 0.07483, 'KER.PA': 0.18292, 'MT.AS': 0.25, 'SGO.PA': 0.02, 'STLAP.PA': 0.02, 'STMPA.PA': 0.18118})" -2016-11-30,9,"OrderedDict({'AIR.PA': 0.02, 'EN.PA': 0.25, 'GLE.PA': 0.25, 'HO.PA': 0.02, 'KER.PA': 0.07592, 'MC.PA': 0.02, 'MT.AS': 0.25, 'STLAP.PA': 0.02, 'STMPA.PA': 0.09408})" -2016-12-30,17,"OrderedDict({'AI.PA': 0.02, 'AIR.PA': 0.02, 'EN.PA': 0.06034, 'GLE.PA': 0.17897, 'KER.PA': 0.02934, 'MC.PA': 0.02, 'ML.PA': 0.02, 'OR.PA': 0.02, 'ORA.PA': 0.21194, 'RNO.PA': 0.02, 'SAF.PA': 0.02, 'SGO.PA': 0.02, 'STLAP.PA': 0.02, 'STMPA.PA': 0.07313, 'SU.PA': 0.02, 'TTE.PA': 0.22628, 'WLN.PA': 0.02})" -2017-01-31,0,{} -2017-02-28,8,"OrderedDict({'AIR.PA': 0.24136, 'ATO.PA': 0.02, 'EN.PA': 0.25, 'HO.PA': 0.17625, 'SAN.PA': 0.02239, 'STLAP.PA': 0.02, 'STMPA.PA': 0.25, 'WLN.PA': 0.02})" -2017-03-31,24,"OrderedDict({'AI.PA': 0.02, 'AIR.PA': 0.02, 'ALO.PA': 0.02, 'ATO.PA': 0.02, 'CAP.PA': 0.02, 'DG.PA': 0.02, 'DSY.PA': 0.02, 'EL.PA': 0.02, 'EN.PA': 0.15819, 'ENGI.PA': 0.25, 'FR.PA': 0.02, 'KER.PA': 0.06452, 'LR.PA': 0.12729, 'MC.PA': 0.02, 'ML.PA': 0.02, 'PUB.PA': 0.02, 'RMS.PA': 0.02, 'SAF.PA': 0.02, 'SAN.PA': 0.02, 'SGO.PA': 0.02, 'STLAP.PA': 0.02, 'VIE.PA': 0.02, 'VIV.PA': 0.02, 'WLN.PA': 0.02})" -2017-04-28,25,"OrderedDict({'AI.PA': 0.02, 'AIR.PA': 0.02, 'ALO.PA': 0.02, 'ATO.PA': 0.02, 'CAP.PA': 0.02, 'DG.PA': 0.02, 'EL.PA': 0.02, 'ERF.PA': 0.05225, 'FR.PA': 0.02, 'GLE.PA': 0.25, 'HO.PA': 0.02, 'KER.PA': 0.10567, 'LR.PA': 0.17207, 'MC.PA': 0.02, 'ML.PA': 0.02, 'OR.PA': 0.02, 'RI.PA': 0.02, 'SAF.PA': 0.02, 'SAN.PA': 0.02, 'SGO.PA': 0.02, 'STLAP.PA': 0.02, 'SU.PA': 0.02, 'TEP.PA': 0.02, 'VIE.PA': 0.02, 'WLN.PA': 0.02})" -2017-05-31,15,"OrderedDict({'ALO.PA': 0.02, 'ATO.PA': 0.02, 'ENGI.PA': 0.25, 'ERF.PA': 0.07003, 'HO.PA': 0.02, 'KER.PA': 0.09424, 'OR.PA': 0.02, 'ORA.PA': 0.25, 'RI.PA': 0.02, 'SAF.PA': 0.13572, 'SAN.PA': 0.02, 'STLAP.PA': 0.02, 'TEP.PA': 0.02, 'VIE.PA': 0.02, 'VIV.PA': 0.02})" -2017-06-30,0,{} -2017-07-31,0,{} -2017-08-31,0,{} -2017-09-29,19,"OrderedDict({'AI.PA': 0.02, 'AIR.PA': 0.02, 'ALO.PA': 0.02, 'BNP.PA': 0.02, 'CS.PA': 0.02, 'EN.PA': 0.25, 'ERF.PA': 0.08566, 'FR.PA': 0.02, 'KER.PA': 0.04098, 'MC.PA': 0.02, 'RNO.PA': 0.02, 'SAF.PA': 0.03118, 'SGO.PA': 0.02, 'STLAP.PA': 0.02, 'STMPA.PA': 0.08219, 'SU.PA': 0.02, 'TEP.PA': 0.02, 'TTE.PA': 0.25, 'VIV.PA': 0.02})" -2017-10-31,19,"OrderedDict({'AI.PA': 0.02, 'AIR.PA': 0.02, 'CAP.PA': 0.02, 'DG.PA': 0.02, 'DSY.PA': 0.02, 'EN.PA': 0.19626, 'KER.PA': 0.05842, 'LR.PA': 0.10797, 'MC.PA': 0.02, 'OR.PA': 0.02, 'RI.PA': 0.02, 'RMS.PA': 0.02, 'SAF.PA': 0.031, 'STLAP.PA': 0.02, 'STMPA.PA': 0.09635, 'SU.PA': 0.02, 'TTE.PA': 0.25, 'VIE.PA': 0.02, 'WLN.PA': 0.02})" -2017-11-30,6,"OrderedDict({'AIR.PA': 0.20448, 'EN.PA': 0.33333, 'ORA.PA': 0.33333, 'RI.PA': 0.02, 'STLAP.PA': 0.02, 'VIE.PA': 0.08886})" -2017-12-29,0,{} -2018-01-31,6,"OrderedDict({'CA.PA': 0.27333, 'CAP.PA': 0.02, 'GLE.PA': 0.33333, 'LR.PA': 0.33333, 'STLAP.PA': 0.02, 'WLN.PA': 0.02})" -2018-02-28,4,"OrderedDict({'AIR.PA': 0.5, 'DSY.PA': 0.02, 'PUB.PA': 0.46, 'STLAP.PA': 0.02})" -2018-03-30,6,"OrderedDict({'ALO.PA': 0.33333, 'DSY.PA': 0.02, 'HO.PA': 0.33333, 'RMS.PA': 0.19025, 'RNO.PA': 0.02, 'STLAP.PA': 0.10308})" -2018-04-30,16,"OrderedDict({'AI.PA': 0.02, 'ALO.PA': 0.02, 'CAP.PA': 0.02, 'ENGI.PA': 0.25, 'HO.PA': 0.02, 'KER.PA': 0.03006, 'MC.PA': 0.02, 'OR.PA': 0.02, 'ORA.PA': 0.21996, 'PUB.PA': 0.02, 'RMS.PA': 0.02, 'SAF.PA': 0.04997, 'STLAP.PA': 0.02, 'TEP.PA': 0.02, 'TTE.PA': 0.23001, 'VIV.PA': 0.02})" -2018-05-31,10,"OrderedDict({'ALO.PA': 0.25, 'DSY.PA': 0.02, 'HO.PA': 0.13, 'KER.PA': 0.25, 'OR.PA': 0.02, 'RI.PA': 0.02, 'RMS.PA': 0.02, 'SAF.PA': 0.25, 'STLAP.PA': 0.02, 'WLN.PA': 0.02})" -2018-06-29,3,"OrderedDict({'ERF.PA': 0.66667, 'STLAP.PA': 0.31333, 'TEP.PA': 0.02})" -2018-07-31,6,"OrderedDict({'CA.PA': 0.33333, 'EL.PA': 0.07114, 'SAN.PA': 0.22219, 'STLAP.PA': 0.02, 'TEP.PA': 0.02, 'TTE.PA': 0.33333})" -2018-08-31,5,"OrderedDict({'DSY.PA': 0.02, 'HO.PA': 0.4, 'SAF.PA': 0.4, 'STLAP.PA': 0.16, 'TEP.PA': 0.02})" -2018-09-28,8,"OrderedDict({'AI.PA': 0.21127, 'CS.PA': 0.1662, 'EL.PA': 0.02, 'HO.PA': 0.06253, 'RI.PA': 0.02, 'SAF.PA': 0.25, 'STLAP.PA': 0.02, 'TTE.PA': 0.25})" -2018-10-31,0,{} -2018-11-30,0,{} -2018-12-31,0,{} -2019-01-31,10,"OrderedDict({'AIR.PA': 0.02, 'CA.PA': 0.25, 'ENGI.PA': 0.25, 'KER.PA': 0.13704, 'MC.PA': 0.02, 'OR.PA': 0.02, 'RMS.PA': 0.02, 'RNO.PA': 0.02, 'SAF.PA': 0.24296, 'STLAP.PA': 0.02})" -2019-02-28,16,"OrderedDict({'AIR.PA': 0.02, 'BNP.PA': 0.02, 'CAP.PA': 0.02, 'CS.PA': 0.02, 'DG.PA': 0.02, 'DSY.PA': 0.02, 'EN.PA': 0.25, 'KER.PA': 0.14836, 'LR.PA': 0.25, 'MC.PA': 0.02, 'ML.PA': 0.02, 'RMS.PA': 0.02, 'SAF.PA': 0.11164, 'STLAP.PA': 0.02, 'SU.PA': 0.02, 'VIV.PA': 0.02})" -2019-03-29,10,"OrderedDict({'AIR.PA': 0.17122, 'DG.PA': 0.22687, 'KER.PA': 0.23191, 'MC.PA': 0.02, 'OR.PA': 0.02, 'ORA.PA': 0.25, 'RI.PA': 0.02, 'RMS.PA': 0.02, 'STLAP.PA': 0.02, 'VIV.PA': 0.02})" -2019-04-30,20,"OrderedDict({'AI.PA': 0.02, 'AIR.PA': 0.02, 'CS.PA': 0.02, 'DG.PA': 0.02, 'DSY.PA': 0.02, 'EN.PA': 0.25, 'ERF.PA': 0.13976, 'FR.PA': 0.02, 'LR.PA': 0.25, 'MC.PA': 0.02, 'ML.PA': 0.02, 'OR.PA': 0.02, 'PUB.PA': 0.02, 'RMS.PA': 0.02, 'SAF.PA': 0.04024, 'SGO.PA': 0.02, 'STLAP.PA': 0.02, 'SU.PA': 0.02, 'VIE.PA': 0.02, 'VIV.PA': 0.02})" -2019-05-31,0,{} -2019-06-28,10,"OrderedDict({'AI.PA': 0.11995, 'EL.PA': 0.02, 'FR.PA': 0.25, 'HO.PA': 0.14871, 'LR.PA': 0.25, 'MC.PA': 0.02, 'RMS.PA': 0.02, 'STLAP.PA': 0.02, 'SU.PA': 0.13134, 'WLN.PA': 0.02})" -2019-07-31,5,"OrderedDict({'AI.PA': 0.16281, 'ALO.PA': 0.39719, 'EL.PA': 0.02, 'STLAP.PA': 0.02, 'VIE.PA': 0.4})" -2019-08-30,5,"OrderedDict({'DG.PA': 0.4, 'EL.PA': 0.13399, 'EN.PA': 0.4, 'RI.PA': 0.02619, 'STLAP.PA': 0.03982})" -2019-09-30,8,"OrderedDict({'CS.PA': 0.02, 'EN.PA': 0.2248, 'ENGI.PA': 0.25, 'ORA.PA': 0.25, 'SAF.PA': 0.1952, 'SAN.PA': 0.02, 'STLAP.PA': 0.02, 'VIE.PA': 0.02})" -2019-10-31,6,"OrderedDict({'AIR.PA': 0.02, 'KER.PA': 0.29001, 'LR.PA': 0.33333, 'OR.PA': 0.02, 'STLAP.PA': 0.02, 'STMPA.PA': 0.31666})" -2019-11-29,13,"OrderedDict({'AI.PA': 0.02, 'ATO.PA': 0.02, 'BNP.PA': 0.02473, 'DSY.PA': 0.02, 'EL.PA': 0.02, 'ERF.PA': 0.19359, 'GLE.PA': 0.25, 'KER.PA': 0.15631, 'MC.PA': 0.02, 'RMS.PA': 0.02, 'STLAP.PA': 0.02, 'STMPA.PA': 0.21537, 'TEP.PA': 0.02})" -2019-12-31,9,"OrderedDict({'AI.PA': 0.02675, 'ALO.PA': 0.08598, 'BNP.PA': 0.12087, 'GLE.PA': 0.25, 'KER.PA': 0.2064, 'STLAP.PA': 0.02, 'STMPA.PA': 0.25, 'VIV.PA': 0.02, 'WLN.PA': 0.02})" -2020-01-31,6,"OrderedDict({'AI.PA': 0.19651, 'ALO.PA': 0.17454, 'ENGI.PA': 0.33333, 'HO.PA': 0.06624, 'STLAP.PA': 0.02, 'VIE.PA': 0.20939})" -2020-02-28,0,{} -2020-03-31,0,{} -2020-04-30,0,{} -2020-05-29,5,"OrderedDict({'DSY.PA': 0.02, 'ERF.PA': 0.4, 'RMS.PA': 0.0646, 'SGO.PA': 0.4, 'STLAP.PA': 0.1154})" -2020-06-30,6,"OrderedDict({'ATO.PA': 0.04513, 'LR.PA': 0.33333, 'OR.PA': 0.2482, 'STLAP.PA': 0.02, 'SU.PA': 0.33333, 'WLN.PA': 0.02})" -2020-07-31,3,"OrderedDict({'AI.PA': 0.66667, 'STLAP.PA': 0.31333, 'TEP.PA': 0.02})" -2020-08-31,0,{} -2020-09-30,0,{} -2020-10-30,0,{} -2020-11-30,16,"OrderedDict({'AIR.PA': 0.02, 'ALO.PA': 0.02, 'ATO.PA': 0.02, 'BNP.PA': 0.02, 'CS.PA': 0.02, 'FR.PA': 0.02, 'GLE.PA': 0.18706, 'MC.PA': 0.02, 'ORA.PA': 0.25, 'PUB.PA': 0.02, 'RI.PA': 0.02, 'RNO.PA': 0.02, 'SAF.PA': 0.02, 'STLAP.PA': 0.02, 'STMPA.PA': 0.07294, 'TTE.PA': 0.25})" -2020-12-31,5,"{'CAP.PA': 0.2, 'DSY.PA': 0.2, 'MC.PA': 0.2, 'RMS.PA': 0.2, 'STLAP.PA': 0.2}" -2021-01-29,0,{} -2021-02-26,7,"OrderedDict({'BNP.PA': 0.28571, 'CS.PA': 0.28571, 'GLE.PA': 0.28571, 'ML.PA': 0.08286, 'PUB.PA': 0.02, 'SGO.PA': 0.02, 'STLAP.PA': 0.02})" -2021-03-31,11,"OrderedDict({'CA.PA': 0.25, 'CAP.PA': 0.02, 'CS.PA': 0.11, 'LR.PA': 0.25, 'OR.PA': 0.02, 'ORA.PA': 0.25, 'PUB.PA': 0.02, 'SAN.PA': 0.02, 'SGO.PA': 0.02, 'STLAP.PA': 0.02, 'TEP.PA': 0.02})" -2021-04-30,13,"OrderedDict({'CA.PA': 0.23184, 'CAP.PA': 0.02, 'CS.PA': 0.02, 'DG.PA': 0.08727, 'GLE.PA': 0.25, 'KER.PA': 0.20052, 'MC.PA': 0.02, 'OR.PA': 0.02, 'RMS.PA': 0.02, 'SAN.PA': 0.02, 'SGO.PA': 0.02, 'VIE.PA': 0.07037, 'WLN.PA': 0.02})" -2021-05-31,11,"OrderedDict({'AIR.PA': 0.02, 'CA.PA': 0.21855, 'ERF.PA': 0.10276, 'GLE.PA': 0.25, 'KER.PA': 0.08508, 'LR.PA': 0.2236, 'MC.PA': 0.02, 'OR.PA': 0.02, 'RI.PA': 0.02, 'RMS.PA': 0.02, 'STLAP.PA': 0.02})" -2021-06-30,8,"OrderedDict({'CAP.PA': 0.18548, 'DSY.PA': 0.02, 'EL.PA': 0.23363, 'ERF.PA': 0.25, 'LR.PA': 0.25, 'RI.PA': 0.02089, 'RMS.PA': 0.02, 'TEP.PA': 0.02})" -2021-07-30,9,"OrderedDict({'CAP.PA': 0.06654, 'DSY.PA': 0.02, 'EL.PA': 0.10346, 'LR.PA': 0.25, 'RMS.PA': 0.02, 'SGO.PA': 0.02, 'STMPA.PA': 0.25, 'TEP.PA': 0.02, 'VIE.PA': 0.25})" -2021-08-31,11,"OrderedDict({'CAP.PA': 0.02, 'DSY.PA': 0.02, 'EL.PA': 0.02, 'EN.PA': 0.25, 'ERF.PA': 0.18266, 'LR.PA': 0.25, 'STMPA.PA': 0.17734, 'SU.PA': 0.02, 'TEP.PA': 0.02, 'VIE.PA': 0.02, 'VIV.PA': 0.02})" -2021-09-30,0,{} -2021-10-29,6,"OrderedDict({'CAP.PA': 0.11621, 'CS.PA': 0.33333, 'DSY.PA': 0.02, 'EL.PA': 0.17713, 'RMS.PA': 0.02, 'STMPA.PA': 0.33333})" -2021-11-30,0,{} -2021-12-31,5,"OrderedDict({'LR.PA': 0.4, 'SU.PA': 0.16, 'TEP.PA': 0.02, 'VIE.PA': 0.4, 'VIV.PA': 0.02})" -2022-01-31,0,{} -2022-02-28,0,{} -2022-03-31,0,{} -2022-04-29,0,{} -2022-05-31,4,"OrderedDict({'ALO.PA': 0.03208, 'FR.PA': 0.02, 'GLE.PA': 0.44792, 'TTE.PA': 0.5})" -2022-06-30,0,{} -2022-07-29,14,"OrderedDict({'CAP.PA': 0.02, 'DSY.PA': 0.02, 'KER.PA': 0.25, 'MC.PA': 0.02, 'OR.PA': 0.02, 'PUB.PA': 0.02, 'RI.PA': 0.02, 'RMS.PA': 0.02, 'RNO.PA': 0.02, 'SAF.PA': 0.25, 'STLAP.PA': 0.02, 'STMPA.PA': 0.25, 'SU.PA': 0.05, 'WLN.PA': 0.02})" -2022-08-31,0,{} -2022-09-30,0,{} -2022-10-31,9,"OrderedDict({'AI.PA': 0.11012, 'AIR.PA': 0.02, 'DG.PA': 0.09797, 'ENGI.PA': 0.25, 'HO.PA': 0.02, 'PUB.PA': 0.02, 'SAF.PA': 0.21191, 'SAN.PA': 0.02, 'TTE.PA': 0.25})" -2022-11-30,14,"OrderedDict({'ALO.PA': 0.03978, 'BNP.PA': 0.02741, 'CS.PA': 0.02, 'DG.PA': 0.02988, 'EL.PA': 0.02, 'ENGI.PA': 0.25, 'KER.PA': 0.10204, 'MC.PA': 0.02, 'PUB.PA': 0.02, 'RMS.PA': 0.02, 'RNO.PA': 0.02, 'SAF.PA': 0.16089, 'STLAP.PA': 0.02, 'TTE.PA': 0.25})" -2022-12-30,0,{} -2023-01-31,13,"OrderedDict({'ALO.PA': 0.02, 'BNP.PA': 0.02, 'CS.PA': 0.02, 'DG.PA': 0.05829, 'GLE.PA': 0.25, 'KER.PA': 0.16772, 'MC.PA': 0.02, 'PUB.PA': 0.02, 'RMS.PA': 0.02, 'SAF.PA': 0.1538, 'STMPA.PA': 0.21019, 'TEP.PA': 0.02, 'VIV.PA': 0.02})" -2023-02-28,12,"OrderedDict({'ALO.PA': 0.03103, 'BNP.PA': 0.06075, 'CA.PA': 0.12175, 'CS.PA': 0.02, 'EN.PA': 0.25, 'HO.PA': 0.02, 'ORA.PA': 0.25, 'PUB.PA': 0.02, 'RNO.PA': 0.02, 'SGO.PA': 0.02, 'STLAP.PA': 0.02, 'STMPA.PA': 0.16647})" -2023-03-31,6,"OrderedDict({'ENGI.PA': 0.33333, 'OR.PA': 0.21677, 'ORA.PA': 0.33333, 'RI.PA': 0.02, 'RMS.PA': 0.02, 'SAN.PA': 0.07656})" -2023-04-28,8,"OrderedDict({'AI.PA': 0.11693, 'DG.PA': 0.02865, 'EN.PA': 0.25, 'ENGI.PA': 0.25, 'OR.PA': 0.06443, 'ORA.PA': 0.25, 'RMS.PA': 0.02, 'VIV.PA': 0.02})" -2023-05-31,0,{} -2023-06-30,5,"OrderedDict({'ENGI.PA': 0.4, 'GLE.PA': 0.4, 'OR.PA': 0.16, 'RNO.PA': 0.02, 'STLAP.PA': 0.02})" -2023-07-31,10,"OrderedDict({'BNP.PA': 0.02, 'CA.PA': 0.20428, 'EN.PA': 0.25, 'ERF.PA': 0.12468, 'GLE.PA': 0.25, 'ML.PA': 0.02, 'RNO.PA': 0.02, 'SAF.PA': 0.07103, 'SGO.PA': 0.02, 'STLAP.PA': 0.02})" -2023-08-31,0,{} -2023-09-29,0,{} -2023-10-31,0,{} -2023-11-30,17,"OrderedDict({'AI.PA': 0.02, 'AIR.PA': 0.02, 'CAP.PA': 0.02, 'DG.PA': 0.02, 'DSY.PA': 0.02, 'EN.PA': 0.10036, 'ENGI.PA': 0.25, 'ML.PA': 0.02, 'OR.PA': 0.02, 'ORA.PA': 0.25, 'PUB.PA': 0.02, 'SAF.PA': 0.06344, 'SGO.PA': 0.02, 'STLAP.PA': 0.02, 'STMPA.PA': 0.0962, 'SU.PA': 0.02, 'VIE.PA': 0.02})" -2023-12-29,10,"OrderedDict({'BNP.PA': 0.25, 'DSY.PA': 0.02, 'ERF.PA': 0.25, 'ML.PA': 0.03586, 'OR.PA': 0.11414, 'PUB.PA': 0.02, 'SGO.PA': 0.02, 'STLAP.PA': 0.02, 'SU.PA': 0.25, 'VIV.PA': 0.02})" -2024-01-31,9,"OrderedDict({'CAP.PA': 0.02, 'CS.PA': 0.20449, 'DSY.PA': 0.02, 'MC.PA': 0.02, 'PUB.PA': 0.02, 'SAF.PA': 0.25, 'SU.PA': 0.19551, 'VIE.PA': 0.25, 'VIV.PA': 0.02})" -2024-02-29,13,"OrderedDict({'AI.PA': 0.15552, 'CAP.PA': 0.02, 'CS.PA': 0.12125, 'EL.PA': 0.02, 'EN.PA': 0.25, 'MC.PA': 0.02, 'ML.PA': 0.02, 'PUB.PA': 0.02, 'RMS.PA': 0.02, 'SAF.PA': 0.25, 'SGO.PA': 0.02, 'STLAP.PA': 0.02, 'SU.PA': 0.06322})" -2024-03-29,17,"OrderedDict({'AI.PA': 0.02, 'AIR.PA': 0.02, 'ALO.PA': 0.02, 'BNP.PA': 0.02, 'CS.PA': 0.02, 'EL.PA': 0.02, 'EN.PA': 0.21294, 'ERF.PA': 0.06038, 'GLE.PA': 0.21668, 'HO.PA': 0.02, 'ML.PA': 0.02, 'PUB.PA': 0.02, 'RMS.PA': 0.02, 'RNO.PA': 0.02, 'SAF.PA': 0.02, 'STLAP.PA': 0.02, 'TTE.PA': 0.25})" -2024-04-30,6,"OrderedDict({'BNP.PA': 0.20889, 'ENGI.PA': 0.33333, 'ML.PA': 0.08444, 'SAN.PA': 0.02, 'SGO.PA': 0.02, 'TTE.PA': 0.33333})" -2024-05-31,8,"OrderedDict({'ALO.PA': 0.10306, 'BNP.PA': 0.08832, 'ENGI.PA': 0.25, 'GLE.PA': 0.25, 'ML.PA': 0.02, 'RNO.PA': 0.02, 'SGO.PA': 0.02, 'VIE.PA': 0.24862})" -2024-06-28,0,{} -2024-07-31,0,{} -2024-08-30,5,"OrderedDict({'CS.PA': 0.03942, 'ENGI.PA': 0.4, 'LR.PA': 0.39602, 'SAN.PA': 0.02, 'VIE.PA': 0.14456})" -2024-09-30,0,{} -2024-10-31,0,{} -2024-11-29,0,{} -2024-12-31,3,"{'RMS.PA': 0.3333333333333333, 'RNO.PA': 0.3333333333333333, 'WLN.PA': 0.3333333333333333}" -2025-01-31,16,"OrderedDict({'AI.PA': 0.02, 'AIR.PA': 0.02, 'BNP.PA': 0.02, 'CAP.PA': 0.02, 'CS.PA': 0.02, 'DSY.PA': 0.02, 'EL.PA': 0.02, 'EN.PA': 0.21301, 'FR.PA': 0.02, 'GLE.PA': 0.25, 'HO.PA': 0.02, 'ORA.PA': 0.25, 'RMS.PA': 0.02, 'RNO.PA': 0.02, 'SAF.PA': 0.04699, 'SAN.PA': 0.02})" -2025-02-28,11,"OrderedDict({'AI.PA': 0.02, 'BNP.PA': 0.02, 'DG.PA': 0.02, 'EL.PA': 0.02, 'EN.PA': 0.1158, 'ENGI.PA': 0.25, 'GLE.PA': 0.19967, 'HO.PA': 0.02, 'ORA.PA': 0.25, 'SAF.PA': 0.06453, 'VIE.PA': 0.02})" -2025-03-31,6,"OrderedDict({'EN.PA': 0.08194, 'ENGI.PA': 0.33333, 'HO.PA': 0.02, 'ORA.PA': 0.22723, 'TTE.PA': 0.3175, 'VIE.PA': 0.02})" -2025-04-30,9,"OrderedDict({'CS.PA': 0.02, 'DG.PA': 0.02, 'EN.PA': 0.12094, 'ENGI.PA': 0.25, 'ERF.PA': 0.09011, 'GLE.PA': 0.20895, 'OR.PA': 0.02, 'ORA.PA': 0.25, 'VIE.PA': 0.02})" -2025-05-30,11,"OrderedDict({'BNP.PA': 0.02, 'CS.PA': 0.02, 'ENGI.PA': 0.25, 'ERF.PA': 0.06736, 'GLE.PA': 0.1518, 'HO.PA': 0.02, 'LR.PA': 0.16084, 'ML.PA': 0.02, 'ORA.PA': 0.25, 'SAF.PA': 0.02, 'VIV.PA': 0.02})" -2025-06-30,6,"OrderedDict({'AIR.PA': 0.02, 'ENGI.PA': 0.33333, 'ERF.PA': 0.18875, 'LR.PA': 0.25397, 'SAF.PA': 0.05924, 'STMPA.PA': 0.14471})" -2025-07-31,7,"OrderedDict({'ERF.PA': 0.17109, 'GLE.PA': 0.28571, 'KER.PA': 0.16476, 'LR.PA': 0.28571, 'OR.PA': 0.02, 'SAF.PA': 0.05271, 'VIV.PA': 0.02})" -2025-08-29,0,{} -2025-09-30,6,"OrderedDict({'AIR.PA': 0.02, 'ATO.PA': 0.02, 'HO.PA': 0.02, 'KER.PA': 0.29109, 'LR.PA': 0.33333, 'SAF.PA': 0.31558})" -2025-10-31,6,"OrderedDict({'AIR.PA': 0.14111, 'EL.PA': 0.02, 'ENGI.PA': 0.33333, 'FR.PA': 0.15222, 'LR.PA': 0.33333, 'MC.PA': 0.02})" -2025-11-28,5,"OrderedDict({'EN.PA': 0.10034, 'ENGI.PA': 0.34661, 'GLE.PA': 0.18662, 'MC.PA': 0.02, 'TTE.PA': 0.34643})" -2025-12-31,9,"OrderedDict({'ALO.PA': 0.02, 'BNP.PA': 0.02, 'CA.PA': 0.14851, 'CS.PA': 0.02, 'EN.PA': 0.21387, 'ENGI.PA': 0.25, 'ERF.PA': 0.08635, 'GLE.PA': 0.22127, 'MC.PA': 0.02})" -2026-01-30,7,"OrderedDict({'BNP.PA': 0.02, 'ENGI.PA': 0.27352, 'GLE.PA': 0.14679, 'ML.PA': 0.02, 'ORA.PA': 0.23398, 'TTE.PA': 0.28571, 'VIE.PA': 0.02})" -2026-02-27,14,"OrderedDict({'AI.PA': 0.02, 'BNP.PA': 0.02, 'CA.PA': 0.02, 'CS.PA': 0.02, 'DG.PA': 0.02, 'EN.PA': 0.02, 'ENGI.PA': 0.24363, 'LR.PA': 0.07194, 'ML.PA': 0.02, 'ORA.PA': 0.21139, 'STMPA.PA': 0.06567, 'SU.PA': 0.02, 'TTE.PA': 0.22736, 'VIE.PA': 0.02})" -2026-03-31,0,{} diff --git a/requirements.txt b/requirements.txt index 789506c..500f13e 100644 --- a/requirements.txt +++ b/requirements.txt @@ -29,4 +29,12 @@ tqdm>=4.66.1 # Web App streamlit>=1.30.0 -streamlit-autorefresh \ No newline at end of file +streamlit-autorefresh + +# Hugging face +huggingface_hub>=0.20.0 +datasets>=2.16.0 +pyarrow>=14.0.0 + +# environnement variables +python-dotenv>=1.0.0 \ No newline at end of file diff --git a/src/analysis/metrics.py b/src/analysis/metrics.py new file mode 100644 index 0000000..e2a0916 --- /dev/null +++ b/src/analysis/metrics.py @@ -0,0 +1 @@ +# Signal-Based diff --git a/src/backtest/backtest.py b/src/backtest/backtest.py new file mode 100644 index 0000000..bb52c69 --- /dev/null +++ b/src/backtest/backtest.py @@ -0,0 +1,299 @@ +from typing import Dict, List, Tuple + +import numpy as np +import pandas as pd + +from src.utils.logger import setup_logger +from src.utils.config_loader import BENCHMARK_TICKER +from src.utils.market_utils import get_benchmark_returns + + +logger = setup_logger("backtest") + + +# ============================================================================= +# COSTS / TURNOVER +# ============================================================================= + +def calculate_turnover_friction( + old_weights: Dict[str, float], + new_weights: Dict[str, float], + fee_bps: float = 0.0020, +) -> Tuple[float, float]: + """ + Calcule: + - le coût de friction en pourcentage du portefeuille + - le turnover réel + """ + total_turnover = 0.0 + all_tickers = set(old_weights.keys()).union(set(new_weights.keys())) + + for ticker in all_tickers: + old_w = old_weights.get(ticker, 0.0) + new_w = new_weights.get(ticker, 0.0) + total_turnover += abs(new_w - old_w) + + true_turnover = total_turnover / 2.0 + friction_cost_pct = true_turnover * fee_bps + + return friction_cost_pct, true_turnover + + +# ============================================================================= +# PORTFOLIO CONSTRUCTION +# ============================================================================= + +def get_topk_equal_weights( + selected: pd.DataFrame, + top_k: int = 5, + score_col: str = "proba_upside", +) -> Dict[str, float]: + """ + Prend les top_k meilleurs titres selon score_col + et attribue des poids égaux. + """ + if selected is None or selected.empty: + return {} + + if score_col not in selected.columns: + logger.warning(f"Column '{score_col}' not found in selected dataframe.") + return {} + + top_selected = selected.sort_values(score_col, ascending=False).head(top_k) + + n_assets = len(top_selected) + if n_assets == 0: + return {} + + weight = 1.0 / n_assets + return {ticker: weight for ticker in top_selected.index.tolist()} + + +# ============================================================================= +# DAILY PATH SIMULATION +# ============================================================================= + +def _simulate_daily_returns( + allocation: Dict[str, float], + trading_days: pd.DatetimeIndex, + daily_returns: pd.DataFrame, + benchmark_returns: pd.Series, + portfolio_value: float, + benchmark_value: float, +) -> Tuple[List[dict], float, float]: + """ + Simule l'évolution quotidienne du portefeuille et du benchmark + entre deux dates de rebalancement. + """ + records: List[dict] = [] + + for current_date in trading_days: + bench_ret = float(benchmark_returns.get(current_date, 0.0)) + strat_ret = 0.0 + + if allocation: + weights = list(allocation.values()) + asset_returns = [] + + for ticker in allocation.keys(): + if ticker in daily_returns.columns and current_date in daily_returns.index: + asset_returns.append(daily_returns.loc[current_date, ticker]) + else: + asset_returns.append(0.0) + + asset_returns = pd.Series(asset_returns).replace([np.inf, -np.inf], np.nan).fillna(0.0) + strat_ret = float(np.average(asset_returns, weights=weights)) + + portfolio_value *= (1 + strat_ret) + benchmark_value *= (1 + bench_ret) + + records.append( + { + "Date": current_date, + "Strategy": portfolio_value, + "Benchmark": benchmark_value, + } + ) + + return records, portfolio_value, benchmark_value + + +# ============================================================================= +# EMPTY OUTPUT HELPERS +# ============================================================================= + +def _empty_history_df() -> pd.DataFrame: + return pd.DataFrame(columns=["Strategy", "Benchmark"]) + + +def _empty_rebalance_df() -> pd.DataFrame: + return pd.DataFrame( + columns=[ + "Method", + "Selected_Count", + "N_Stocks", + "Turnover", + "Cost_Pct", + "Allocation", + ] + ) + + +# ============================================================================= +# MAIN BACKTEST +# ============================================================================= + +def backtest_strategy_with_rebalancing( + df_daily: pd.DataFrame, + signal_generator, + top_k: int = 5, + target_cluster: int = 1, + proba_threshold: float = 0.55, + fee_bps: float = 0.0020, +) -> Tuple[pd.DataFrame, pd.DataFrame]: + """ + Backtest Top-k avec: + - filtrage cluster + seuil de proba + - pondération égale + - coûts de turnover + - benchmark de marché + """ + logger.info("Starting backtest | method=topk") + + if df_daily is None or df_daily.empty: + logger.warning("df_daily is empty. Returning empty backtest outputs.") + return _empty_history_df(), _empty_rebalance_df() + + if "adj close" not in df_daily.columns: + logger.error("Missing 'adj close' column in df_daily.") + return _empty_history_df(), _empty_rebalance_df() + + try: + daily_prices = df_daily["adj close"].unstack().sort_index().ffill() + except Exception as e: + logger.error(f"Failed to reshape daily prices: {e}") + return _empty_history_df(), _empty_rebalance_df() + + if daily_prices.empty: + logger.warning("daily_prices is empty after unstack.") + return _empty_history_df(), _empty_rebalance_df() + + daily_returns = ( + daily_prices.pct_change() + .replace([np.inf, -np.inf], np.nan) + .fillna(0.0) + ) + + date_min = df_daily.index.get_level_values("date").min() + date_max = df_daily.index.get_level_values("date").max() + + benchmark_returns = get_benchmark_returns( + BENCHMARK_TICKER, + date_min, + date_max, + daily_prices.index, + ) + + if benchmark_returns is None or len(benchmark_returns) == 0: + benchmark_returns = pd.Series(0.0, index=daily_prices.index) + else: + benchmark_returns = ( + benchmark_returns.reindex(daily_prices.index) + .replace([np.inf, -np.inf], np.nan) + .fillna(0.0) + ) + + monthly_dates = ( + signal_generator.signal_cache.index.get_level_values("date") + .unique() + .sort_values() + ) + + if len(monthly_dates) < 2: + logger.warning("Not enough monthly dates to run backtest.") + return _empty_history_df(), _empty_rebalance_df() + + portfolio_value = 100.0 + benchmark_value = 100.0 + all_records: List[dict] = [] + rebalance_log: List[dict] = [] + previous_allocation: Dict[str, float] = {} + + for month_date, next_month in zip(monthly_dates[:-1], monthly_dates[1:]): + month_data = signal_generator.get_signal(month_date) + + allocation: Dict[str, float] = {} + selected_count = 0 + + if month_data is not None and not month_data.empty: + required_cols = {"cluster", "proba_upside"} + if required_cols.issubset(month_data.columns): + selected = month_data[ + (month_data["cluster"] == target_cluster) & + (month_data["proba_upside"] >= proba_threshold) + ].copy() + + selected_count = len(selected) + + if not selected.empty: + allocation = get_topk_equal_weights( + selected=selected, + top_k=top_k, + score_col="proba_upside", + ) + else: + logger.warning( + f"Signal dataframe missing required columns: {required_cols - set(month_data.columns)}" + ) + + cost_pct, turnover = calculate_turnover_friction( + previous_allocation, + allocation, + fee_bps=fee_bps, + ) + + portfolio_value *= (1 - cost_pct) + previous_allocation = allocation.copy() + + trading_days = daily_prices.index[ + (daily_prices.index >= month_date) & (daily_prices.index < next_month) + ] + + if len(trading_days) > 0: + day_records, portfolio_value, benchmark_value = _simulate_daily_returns( + allocation=allocation, + trading_days=trading_days, + daily_returns=daily_returns, + benchmark_returns=benchmark_returns, + portfolio_value=portfolio_value, + benchmark_value=benchmark_value, + ) + all_records.extend(day_records) + + rebalance_log.append( + { + "Date": month_date, + "Method": "topk", + "Selected_Count": selected_count, + "N_Stocks": len(allocation), + "Turnover": turnover, + "Cost_Pct": cost_pct, + "Allocation": allocation, + } + ) + + logger.info(f"Backtest complete. Final value: {portfolio_value:.2f}") + + hist_df = ( + pd.DataFrame(all_records).set_index("Date").sort_index() + if all_records + else _empty_history_df() + ) + + rebal_df = ( + pd.DataFrame(rebalance_log).set_index("Date").sort_index() + if rebalance_log + else _empty_rebalance_df() + ) + + return hist_df, rebal_df \ No newline at end of file diff --git a/src/backtest/executor.py b/src/backtest/executor.py new file mode 100644 index 0000000..1a0ee6e --- /dev/null +++ b/src/backtest/executor.py @@ -0,0 +1 @@ +# backtest_strategy_with_rebalancing diff --git a/src/data/daily_raw.parquet b/src/data/daily_raw.parquet new file mode 100644 index 0000000..346ee42 Binary files /dev/null and b/src/data/daily_raw.parquet differ diff --git a/src/data/daily_raw_cac40.parquet b/src/data/daily_raw_cac40.parquet new file mode 100644 index 0000000..a8493b3 Binary files /dev/null and b/src/data/daily_raw_cac40.parquet differ diff --git a/src/data/daily_raw_market_config.parquet b/src/data/daily_raw_market_config.parquet new file mode 100644 index 0000000..c463002 Binary files /dev/null and b/src/data/daily_raw_market_config.parquet differ diff --git a/src/data/daily_raw_nasdaq.parquet b/src/data/daily_raw_nasdaq.parquet new file mode 100644 index 0000000..f4e26ed Binary files /dev/null and b/src/data/daily_raw_nasdaq.parquet differ diff --git a/src/data/daily_raw_sp500.parquet b/src/data/daily_raw_sp500.parquet new file mode 100644 index 0000000..9629307 Binary files /dev/null and b/src/data/daily_raw_sp500.parquet differ diff --git a/src/data/monthly_features.parquet b/src/data/monthly_features.parquet new file mode 100644 index 0000000..29f8cf0 Binary files /dev/null and b/src/data/monthly_features.parquet differ diff --git a/src/data/monthly_features_cac40.parquet b/src/data/monthly_features_cac40.parquet new file mode 100644 index 0000000..dab06cf Binary files /dev/null and b/src/data/monthly_features_cac40.parquet differ diff --git a/src/data/monthly_features_market_config.parquet b/src/data/monthly_features_market_config.parquet new file mode 100644 index 0000000..c0eb47e Binary files /dev/null and b/src/data/monthly_features_market_config.parquet differ diff --git a/src/data/monthly_features_nasdaq.parquet b/src/data/monthly_features_nasdaq.parquet new file mode 100644 index 0000000..c608138 Binary files /dev/null and b/src/data/monthly_features_nasdaq.parquet differ diff --git a/src/data/monthly_features_sp500.parquet b/src/data/monthly_features_sp500.parquet new file mode 100644 index 0000000..fc9223a Binary files /dev/null and b/src/data/monthly_features_sp500.parquet differ diff --git a/src/dataset/builder.py b/src/dataset/builder.py new file mode 100644 index 0000000..0705b0c --- /dev/null +++ b/src/dataset/builder.py @@ -0,0 +1 @@ +# Dataframe \ No newline at end of file diff --git a/src/dataset/processor.py b/src/dataset/processor.py new file mode 100644 index 0000000..b70ec63 --- /dev/null +++ b/src/dataset/processor.py @@ -0,0 +1 @@ +# alpha158 : Qlib \ No newline at end of file diff --git a/src/models/trainer.py b/src/models/trainer.py new file mode 100644 index 0000000..b715767 --- /dev/null +++ b/src/models/trainer.py @@ -0,0 +1 @@ +# Manage walk-Forward , Rolling window \ No newline at end of file diff --git a/src/pipeline/backtest.py b/src/pipeline/backtest.py deleted file mode 100644 index 481ec39..0000000 --- a/src/pipeline/backtest.py +++ /dev/null @@ -1,134 +0,0 @@ -from typing import Any, Dict, Tuple -import numpy as np -import pandas as pd -from pypfopt import EfficientFrontier, risk_models, expected_returns - -from const import ( - TARGET_CLUSTER, - PROBA_THRESHOLD, - FEATURE_COLS, - TRADING_DAYS_YEAR, - RISK_FREE_RATE -) -from src.utils.logger import setup_logger -from src.utils.config_loader import BENCHMARK_TICKER -from src.utils.market_utils import get_benchmark_returns - -logger = setup_logger("backtest") - - -def get_optimal_weights(prices_df: pd.DataFrame) -> Tuple[Dict[str, float], bool]: - try: - mu = expected_returns.mean_historical_return(prices_df, frequency=TRADING_DAYS_YEAR) - S = risk_models.CovarianceShrinkage(prices_df, frequency=TRADING_DAYS_YEAR).ledoit_wolf() - - ef = EfficientFrontier(mu, S, weight_bounds=(0.02, 0.25)) - ef.max_sharpe(risk_free_rate=RISK_FREE_RATE) - - return dict(ef.clean_weights()), True - except Exception as e: - logger.warning(f"Optimization failed: {e}") - return {}, False - - -def _generate_monthly_signals( - month_data: pd.DataFrame, - xgb_model: Any, - kmeans_model: Any, -) -> pd.DataFrame: - if "rsi" in month_data.columns: - month_data = month_data.copy() - month_data["cluster"] = kmeans_model.predict(month_data[["rsi"]].fillna(50)) - - if not all(c in month_data.columns for c in FEATURE_COLS): - return pd.DataFrame() - - month_data["proba_upside"] = xgb_model.predict_proba(month_data[FEATURE_COLS].fillna(0))[:, 1] - return month_data - - -def _simulate_daily_returns( - allocation: Dict[str, float], - trading_days: pd.DatetimeIndex, - daily_returns: pd.DataFrame, - benchmark_returns: pd.Series, - portfolio_value: float, - benchmark_value: float, -) -> Tuple[list, float, float]: - records = [] - for date in trading_days: - bench_ret = benchmark_returns.get(date, 0.0) - strat_ret = 0.0 - - if allocation: - weights = list(allocation.values()) - rets = [ - daily_returns.loc[date, t] if t in daily_returns.columns and date in daily_returns.index else 0.0 - for t in allocation - ] - strat_ret = float(np.average(pd.Series(rets).fillna(0), weights=weights)) - - portfolio_value *= (1 + strat_ret) - benchmark_value *= (1 + bench_ret) - records.append({"Date": date, "Strategy": portfolio_value, "Benchmark": benchmark_value}) - - return records, portfolio_value, benchmark_value - - -def backtest_strategy_with_rebalancing( - df_daily: pd.DataFrame, - df_monthly: pd.DataFrame, - xgb_model: Any, - kmeans_model: Any, - get_optimal_weights_fn: Any, -) -> Tuple[pd.DataFrame, pd.DataFrame]: - logger.info("Starting backtest...") - - daily_prices = df_daily["adj close"].unstack().ffill() - daily_returns = daily_prices.pct_change().fillna(0) - - date_min = df_daily.index.get_level_values("date").min() - date_max = df_daily.index.get_level_values("date").max() - - benchmark_returns = get_benchmark_returns( - BENCHMARK_TICKER, date_min, date_max, daily_prices.index - ) - - portfolio_value, benchmark_value = 100.0, 100.0 - all_records, rebalance_log = [], [] - monthly_dates = df_monthly.index.get_level_values("date").unique().sort_values() - - for i, month_date in enumerate(monthly_dates[:-1]): - month_data = _generate_monthly_signals( - df_monthly.xs(month_date, level="date").copy(), - xgb_model, - kmeans_model, - ) - - allocation: Dict[str, float] = {} - if not month_data.empty: - selected = month_data[ - (month_data["cluster"] == TARGET_CLUSTER) & - (month_data["proba_upside"] > PROBA_THRESHOLD) - ] - - if not selected.empty: - tickers = selected.index.tolist() - prices_subset = daily_prices[tickers].iloc[-TRADING_DAYS_YEAR:].dropna(axis=1) - - if not prices_subset.empty and len(prices_subset.columns) >= 3: - weights, success = get_optimal_weights_fn(prices_subset) - allocation = weights if success else {t: 1.0 / len(tickers) for t in tickers} - - next_month = monthly_dates[i + 1] - trading_days = daily_prices.index[(daily_prices.index >= month_date) & (daily_prices.index < next_month)] - - day_records, portfolio_value, benchmark_value = _simulate_daily_returns( - allocation, trading_days, daily_returns, - benchmark_returns, portfolio_value, benchmark_value, - ) - all_records.extend(day_records) - rebalance_log.append({"Date": month_date, "N_Stocks": len(allocation), "Allocation": allocation}) - - logger.info(f"Backtest complete. Final value: {portfolio_value:.2f}") - return pd.DataFrame(all_records).set_index("Date"), pd.DataFrame(rebalance_log).set_index("Date") \ No newline at end of file diff --git a/src/pipeline/etl.py b/src/pipeline/etl.py index 43ef670..f410410 100644 --- a/src/pipeline/etl.py +++ b/src/pipeline/etl.py @@ -14,7 +14,8 @@ get_fama_french_betas ) from src.transform.ticker_manager import handle_ticker_changes, validate_and_clean_tickers -from src.utils.config_loader import TICKERS +# Importation de la fonction de chargement au lieu de la variable statique +from src.utils.config_loader import load_market_config from src.utils.logger import setup_logger logger = setup_logger("etl") @@ -68,12 +69,23 @@ def _resample_to_monthly(df: pd.DataFrame) -> pd.DataFrame: return monthly -def get_data_pipeline() -> Tuple[Optional[pd.DataFrame], Optional[pd.DataFrame]]: - """Full ETL pipeline orchestrator.""" +def get_data_pipeline(config_file: str = "cac40.json") -> Tuple[Optional[pd.DataFrame], Optional[pd.DataFrame]]: + """ + Full ETL pipeline orchestrator. + Désormais dynamique : utilise le fichier de config passé en argument. + """ + # CHARGEMENT DYNAMIQUE DE LA CONFIG + config = load_market_config(config_file) + tickers_to_load = config.get('assets', []) + + if not tickers_to_load: + logger.error(f"No tickers found in {config_file}") + return None, None + ticker_changes, delisted = handle_ticker_changes() active_tickers = [ ticker_changes.get(t, t) - for t in TICKERS + for t in tickers_to_load if t not in delisted ] @@ -99,9 +111,11 @@ def get_data_pipeline() -> Tuple[Optional[pd.DataFrame], Optional[pd.DataFrame]] logger.info(f"Saving raw data to {DATA_DIR}...") DATA_DIR.mkdir(parents=True, exist_ok=True) - df.to_parquet(DATA_DIR / "daily_raw.parquet", compression="gzip") + + # On ajoute un suffixe au nom du fichier pour éviter que les marchés s'écrasent entre eux + suffix = config_file.replace('.json', '') + df.to_parquet(DATA_DIR / f"daily_raw_{suffix}.parquet", compression="gzip") - # Calcul des indicateurs (la fonction corrigée) df = compute_technical_indicators(df) logger.info("Resampling to monthly frequency...") @@ -109,25 +123,21 @@ def get_data_pipeline() -> Tuple[Optional[pd.DataFrame], Optional[pd.DataFrame]] df_monthly = df_monthly.groupby(level=1, group_keys=False).apply(calculate_returns) df_monthly = get_fama_french_betas(df_monthly) - # Ajout des lags for col in VARS_TO_LAG: if col in df_monthly.columns: df_monthly[f"{col}_lag1"] = df_monthly.groupby("ticker")[col].shift(1) logger.info("Saving monthly features...") - df_monthly.to_parquet(DATA_DIR / "monthly_features.parquet", compression="gzip") + df_monthly.to_parquet(DATA_DIR / f"monthly_features_{suffix}.parquet", compression="gzip") return df, df_monthly def load_models() -> Tuple[Optional[Any], Optional[Any]]: - """ - Charge les modèles pré-entraînés XGBoost et KMeans depuis le dossier MODEL_DIR. - """ + """Charge les modèles pré-entraînés XGBoost et KMeans.""" from const import MODEL_DIR logger.info(f"Loading ML models from {MODEL_DIR}...") try: - # On s'assure que les fichiers existent avant d'ouvrir xgb_path = MODEL_DIR / 'xgboost_model.pkl' kmeans_path = MODEL_DIR / 'kmeans_model.pkl' if not xgb_path.exists() or not kmeans_path.exists(): @@ -141,4 +151,4 @@ def load_models() -> Tuple[Optional[Any], Optional[Any]]: return xgb, kmeans except Exception as e: logger.error(f"Error loading models: {e}") - return None, None + return None, None \ No newline at end of file diff --git a/src/strategy/optimizer.py b/src/strategy/optimizer.py new file mode 100644 index 0000000..f5ecc12 --- /dev/null +++ b/src/strategy/optimizer.py @@ -0,0 +1 @@ +# PyPorfolioOp \ No newline at end of file diff --git a/src/strategy/signals.py b/src/strategy/signals.py new file mode 100644 index 0000000..e4de994 --- /dev/null +++ b/src/strategy/signals.py @@ -0,0 +1,31 @@ +# TopK DropOut + +# src/strategy/signals.py +import pandas as pd +from typing import Any, List + + +class AlphaSignal: + def __init__(self, predictions_df: pd.DataFrame): + # C'est ici que l'attribut est créé + self.signal_cache = predictions_df.sort_index() + + @classmethod + def from_xgboost_kmeans(cls, df_features: pd.DataFrame, xgb_model: Any, kmeans_model: Any, feature_cols: List[str]): + df_preds = df_features.copy() + + # Prédictions vectorisées + if "rsi" in df_preds.columns: + df_preds["cluster"] = kmeans_model.predict(df_preds[["rsi"]].fillna(50)) + + df_preds["proba_upside"] = xgb_model.predict_proba(df_preds[feature_cols].fillna(0))[:, 1] + + # CRITIQUE : On retourne une instance de la classe + # Cela va appeler le __init__ et créer signal_cache + return cls(df_preds[["proba_upside", "cluster"]]) + + def get_signal(self, target_date: pd.Timestamp) -> pd.DataFrame: + try: + return self.signal_cache.xs(target_date, level="date") + except (KeyError, AttributeError): + return pd.DataFrame() \ No newline at end of file diff --git a/src/utils/config_loader.py b/src/utils/config_loader.py index 16b8a7c..c82e753 100644 --- a/src/utils/config_loader.py +++ b/src/utils/config_loader.py @@ -1,33 +1,67 @@ import json -from typing import Dict, Any -from const import CONFIG_FILE +import os +from typing import Dict, Any, List from src.utils.logger import setup_logger +from const import CONFIG_DIR logger = setup_logger("ConfigLoader") -def load_market_config() -> Dict[str, Any]: - """Loads market configuration from JSON file with safe fallbacks.""" - default_config = { - "market_name": "Default (CAC40)", +def load_market_config(config_name: str) -> Dict[str, Any]: + """ + Charge une configuration de marché spécifique depuis un fichier JSON. + Par défaut, tente de charger le CAC 40. + """ + target_path = CONFIG_DIR / config_name + + # Valeurs de secours (au cas où le fichier JSON est corrompu ou absent) + default_fallback = { + "market_name": "CAC 40 (France)", "benchmark_ticker": "^FCHI", - "assets": ["AI.PA", "AIR.PA", "SAN.PA", "MC.PA"] + "currency": "EUR", + "assets": ["AI.PA", "AIR.PA", "OR.PA", "MC.PA", "SAN.PA"] } - if CONFIG_FILE.exists(): - logger.info(f"Loading configuration from: {CONFIG_FILE}") - try: - with open(CONFIG_FILE, 'r') as f: - return json.load(f) - except json.JSONDecodeError as e: - logger.error(f"Invalid JSON in config file: {e}. Using defaults.") - else: - logger.warning(f"Config file not found at {CONFIG_FILE}. Using defaults.") - return default_config - - -MARKET_CONFIG = load_market_config() -TICKERS = MARKET_CONFIG.get('assets', []) -BENCHMARK_TICKER = MARKET_CONFIG.get('benchmark_ticker', '^FCHI') -MARKET_NAME = MARKET_CONFIG.get('market_name', 'Unknown Market') - -logger.info(f"Market: {MARKET_NAME} | Assets: {len(TICKERS)} | Benchmark: {BENCHMARK_TICKER}") + + if not target_path.exists(): + logger.warning( + f"Fichier {config_name} introuvable dans {CONFIG_DIR}. Utilisation du fallback." + ) + + return default_fallback + + try: + with open(target_path, 'r', encoding='utf-8') as f: + config_data = json.load(f) + logger.info(f"Configuration chargée : {config_name}") + return config_data + except json.JSONDecodeError as e: + logger.error(f"Erreur de syntaxe JSON dans {target_path} : {e}") + return default_fallback + except Exception as e: + logger.error(f"Erreur imprévue lors du chargement de {target_path} : {e}") + return default_fallback + + +def get_available_configs() -> List[str]: + """Liste tous les fichiers .json disponibles pour le menu de l'App.""" + return [f.name for f in CONFIG_DIR.glob("*.json")] + +# ============================================================================= +# INITIALISATION AUTOMATIQUE +# ============================================================================= + +# 1. On donne la priorité au CAC 40 par défaut +# La variable d'env permet de changer sans toucher au code (ex: pour GitHub Actions) + + +selected_market_file = os.getenv("MARKET_TYPE", "cac40.json") + +# 2. Chargement des données +MARKET_CONFIG = load_market_config(selected_market_file) + +TICKERS: List[str] = MARKET_CONFIG.get('assets', []) +BENCHMARK_TICKER: str = MARKET_CONFIG.get('benchmark_ticker', '^FCHI') +MARKET_NAME: str = MARKET_CONFIG.get('market_name', 'CAC 40') +CURRENCY: str = MARKET_CONFIG.get('currency', 'EUR') + +logger.info(f"AlphaEdge prêt pour {MARKET_NAME} | {len(TICKERS)} tickers | Devise: {CURRENCY}") \ No newline at end of file diff --git a/src/utils/settings.py b/src/utils/settings.py new file mode 100644 index 0000000..d3ac85b --- /dev/null +++ b/src/utils/settings.py @@ -0,0 +1,35 @@ +from pathlib import Path +import os +from dotenv import load_dotenv +import yaml +from datetime import date + +BASE_DIR = Path(__file__).resolve().parents[2] +CONFIG_PATH = BASE_DIR / "config" / "backtest_config.yaml" + +load_dotenv(BASE_DIR / ".env") + +with open(CONFIG_PATH, "r", encoding="utf-8") as f: + _cfg = yaml.safe_load(f) + +SETTINGS = { + "BASE_DIR": BASE_DIR, + "CONFIG_DIR": BASE_DIR / "config", + "DATA_DIR": BASE_DIR / "data", + "MODEL_DIR": BASE_DIR / "src" / "models", + "LOG_DIR": BASE_DIR / "logs", + + "MARKET_NAME": _cfg.get("market", {}).get("name", "CAC40"), + "MARKET_SUFFIX": _cfg.get("market", {}).get("suffix", "cac40"), + + "TARGET_CLUSTER": _cfg["strategy"]["target_cluster"], + "PROBA_THRESHOLD": _cfg["strategy"]["proba_threshold"], + "FEATURE_COLS": _cfg["strategy"]["feature_cols"], + + "TRADING_DAYS_YEAR": _cfg["backtest"].get("trading_days_year", 252), + "RISK_FREE_RATE": _cfg["backtest"].get("risk_free_rate", 0.02), + "END_TIME": _cfg["backtest"].get("end_time") or date.today().strftime("%Y-%m-%d"), + + "HF_TOKEN": os.getenv("HF_TOKEN"), + "REPO_ID": _cfg.get("huggingface", {}).get("repo_id", "soradata/alphaedge-data"), +} \ No newline at end of file diff --git a/tests/test_hf.py b/tests/test_hf.py new file mode 100644 index 0000000..7f1590a --- /dev/null +++ b/tests/test_hf.py @@ -0,0 +1,15 @@ +import os +from huggingface_hub import HfApi + +# On récupère le token +token = os.getenv("HF_TOKEN") + +if not token: + print(" Erreur : La variable d'environnement HF_TOKEN est vide !") +else: + api = HfApi() + try: + user_info = api.whoami(token=token) + print(f"✅ Connecté avec succès en tant que : {user_info['name']}") + except Exception as e: + print(f" Erreur d'authentification : {e}") \ No newline at end of file diff --git a/ticker_validation.json b/ticker_validation.json index aa76baf..d4c7e1a 100644 --- a/ticker_validation.json +++ b/ticker_validation.json @@ -1,5 +1,5 @@ { - "date": "2026-04-01 19:49:53.741004", + "date": "2026-05-06 18:10:46.341836", "alerts": { "delisted": [], "stale": [],