Галоўная / Артыкулы / Мнага-эйянтныя дыялогі для оптымізацыі пры выходзе на валатыльнасць: чы можа троха Gemini

Мнага-эйянтныя дыялогі для оптымізацыі пры выходзе на валатыльнасць: чы можа троха Gemini

Практычныя інструкцыі па использованні методу багатоагентных дэбатаў для оптымізацыі ситуацый высокай волатыльнасці: трэй Геміні – контракты, перакрытчыкі та спецыяльныя слоты для коду, якія можна выкарыстоўваць командам, якія реалізуюць гэты патэрн.

3043 слоў

Авары, які прыводзяцься пасля гэтых заўважэнняў, апісваюць практычны падход да рашэння задачы «Дебаты калькольнікаў для оптымізацыі выйску з валатыльнасці: чы можа трое персонажаў Gemini выправіць няэфектывную стратэгію?». Акцэнт ставяцца на контрактах, перакананнях і месцах для коду, а не на мотывацыйных аспектах. Калі працуеце на стадыі агляду, спачатку запісайце контракт: неабходныя даны, сігнал успеху і тое, што выканаецца у разе частковага няудачы. Такі список дапамагае заліцварыць пазнейшыя змены ў кодзе. Валіце маленькія, тэставаныя елементы замест большых скрыптов. Калі якісь крок не выйшоў, няудача должна вказваць на адну конкрэтную адпаведальнасц, а не на заплутаны ланцужок задач.

{
    "strategy_version": "v2.0-optimized",
    "final_sharpe_ratio": -0.6822300207528283,
    "consensus_rationale": "Iteration 1 consensus achieved superior Sharpe ratio through optimized ATR multiplier and volume threshold refinement.",
    "max_drawdown_delta": 0.00687485272186061,
    "total_iterations_run": 3
}

Завантажэнне дадзеных і налаштавання рынку

Процес загрузкі кантэнтаў і стадія рынку працюе наякша, калі яго спрыяваць як мерыемую паверхню. Запісаце адна ідеальная версія, адзін прыклад неудачы і запіс пра вярнэнне да пачатковага стану перш чым расширваць масштабы. Спрыявайце гэтую стадію як кантракт межа вхіднымі даннымі і перакананымі выходнымі рэзультатамі. Даўце назвы всім элементам, задаце критэрыя успеху і не падтрымайце тыхія частковыя завершэння. Зафіксавайце інтэрпретара і файл з правіламі залежнасцей пры тым, як выучаеце цикл. Разлік межа ноутбукам і системай CI ёсць найчыстае тыхое нарушэння пад час деманстрацый API.

Проектаванне высокабетаўскага ўніверсуму

Апарат «Проектаванне высокабетаўскага всесвята» працуе наякша, калі яго спрыята як мерымая паверхня. Зафіксавайце адну «золатую» транскрыпцыю, адзін прыклад неудачы і запіс пра вярнэнне да поперадньага стану пры расшырэнні масштаба. Запісвайце часы выконання і косты токеноў або запытак па боку ад функцыйнальных рэзультатаў. Візуабельнасць костаў з самага пачатку запобегае неспакойным рахункам, калі процес пераходзіць з дэмаверсіі ў спяльныя сераўы. Закрепіце інтэрпретара і файл з правіламі залежнасцяў пры навчанні циклу. Разлік межаў між ноутбукам і системай CI ёсць найпашырэнейшым таямным абараненням працы дэмаверсій API.

import os
import json
import logging
from datetime import datetime, timezone
import pandas as pd
import numpy as np
import yfinance as yf
import matplotlib.pyplot as plt
from google import genai
logging.basicConfig(level=logging.INFO,
                    format='%(asctime)s - %(levelname)s - %(message)s')

Работа з нехваткай дадзеных і выравнаванне MultiIndex

Кніга «Handling Missing Data and stage» працюе наявнасць лепш, калі яе спрыяваць як мерыемую паверхню. Зберагачыце адны ідеальны прыклад выкарыстоўвання, адны прыклад неудачы і запіс пра вярнэнне да пачатковага стану перш чым расширваць сферу дзеяння. Храніце настройкі параду ад коду прыемліка. Файлы сераўнавання сяродовы, хранілішча секрэтных дадзеных і флагі функцыйяў должны знаходзіцца ў аднам месцы, куды аператары можаць адбавляць контроль без неабяжнага чытання всіх дадзеных. Закрепіце інтэрпретара і файл з правіламі завісання залежнасцяў перш чым выучаць циклы. Разніця межу ноутбукам і системай CI ёсць найчастэйшым таямным бягам для дэманстрацый API. Кніга «Handling Missing Data and stage» працюе наявнасць лепш, калі яе спрыяваць як мерыемую паверхню. Зберагачыце адны ідеальны прыклад выкарыстоўвання, адны прыклад неудачы і запіс пра вярнэнне да пачатковага стану перш чым расширваць сферу дзеяння. Валіце маленькія, тэставаныя елементы працы над вялікімі скрыптамі. Калі якісь крок не выйшае, прычына неудачы должна вказываць на адну конкрэтную адпаведальнасць, а не на заплутаны ланцуг задач.

class MarketDataLoader:
    def __init__(self, tickers: list[str], benchmark: str):
        self.tickers = tickers
        self.all_symbols = tickers + [benchmark]
        self.benchmark = benchmark

    def fetch_data(self) -> tuple[pd.DataFrame, pd.DataFrame, pd.DataFrame, pd.DataFrame]:
        end_date = datetime.now(timezone.utc).strftime('%Y-%m-%d')
        start_date = (datetime.now(timezone.utc) -
                      pd.Timedelta(days=365 * 3)).strftime('%Y-%m-%d')
        logging.info(
            f"Fetching historical data from {start_date} to {end_date} for {len(self.all_symbols)} symbols.")

        data = yf.download(self.all_symbols, start=start_date,
                           end=end_date, auto_adjust=True, progress=False)
        if data.empty:
            logging.error(
                f"Failed to download data for symbols: {self.all_symbols}")
            raise ValueError(
                f"Failed to download data for symbols: {self.all_symbols}")

        if isinstance(data.columns, pd.MultiIndex):
            close = data['Close'] if 'Close' in data.columns.levels[0] else data.xs(
                'Close', level=1, axis=1)
            high = data['High'] if 'High' in data.columns.levels[0] else data.xs(
                'High', level=1, axis=1)
            low = data['Low'] if 'Low' in data.columns.levels[0] else data.xs(
                'Low', level=1, axis=1)
            volume = data['Volume'] if 'Volume' in data.columns.levels[0] else data.xs(
                'Volume', level=1, axis=1)
        else:
            close = data[['Close']]
            high = data[['High']]
            low = data[['Low']]
            volume = data[['Volume']]

        close = close.ffill().dropna(how='all')
        high = high.ffill().dropna(how='all')
        low = low.ffill().dropna(how='all')
        volume = volume.ffill().fillna(0.0)

        if close.empty:
            logging.error(
                "Cleaned price data DataFrame is empty after processing.")
            raise ValueError(
                "Cleaned price data DataFrame is empty after processing.")

        logging.info(
            f"Data checkpoint - Shape: {close.shape}, Column sample: {list(close.columns[:3])}, NaN count: {close.isna().sum().sum()}, Date range: {close.index[0]} to {close.index[-1]}")
        return close, high, low, volume
INFO - Fetching historical data from 2023-08-10 to 2026-08-09 for 16 symbols.
INFO - Data checkpoint - Shape: (751, 16), Column sample: ['AMD', 'COIN', 'DKNG'], NaN count: 0, Date range: 2023-08-10 00:00:00 to 2026-08-07 00:00:00

Апраначык механізма выяўлення змянення волатыльнасці

У стадзіі апраначыку механізма выяўлення змянення волатыльнасці неабходна праказаць параметры вхідных дадзеных, адпаведальную особу за выкананне крока і критэрыя завершэння працы перад змінайом коду. Аператары должны магчымае перзапускіць крок з вядомай точкі контролю, не падозрываючы прыхованы стан. Цю стадзію трэба спрыяваць як кантракт між вхіднымі дадзенымі і перакананымі выходнымі рэзультатамі. Назваць всі неабходныя элементы, праказаць критэрыі успеху і не дазволяць тыхаму частковаму завершэнню задання. Аддзеліць процес стварэння кліента ад циклу обмену паведамленнямі, ўжо каб было можна змяніць прадаўця без перапісвання машыны стану дыялогу.

Аўтар: «Механіка момэнту і волатыльнасці»

Для стадіі «Механіка імпульсу» автора неабяжна падзець апрацаваць вхідныя даны, абонента крока і крэтырыя выходу пры перадзеіснаванні коду. Аператары должны магчымаць перзапуск крока з вядомай точкі контролю, не спрабоўваючы з’ясаваць захаваны стан. Запісваюцца часы выконання і косты токенаў або запытак праза функцыйнае рэзультат. Відкрытая візуабілізацыя костоў запобегае неспакойным рахункам, калі траекторыя пераходзіць з дэмавай версіі ў спадзеленыя среды. Раздзеляйце стварэнне кліента ад цыклу паведамленняў, каб было можна змяніць прадаўцаў без перапісвання машыны стану размовы.

Сімуляцыя дохадаў портфеля

Для стадіі сімуляцыі дохадкаў портфеля неабходна перш чым зменяць код, апрацаваць параметры вхідных дадзеных, абярнучага этапу і крэтарыі выходу. Аператары должны магчымаць перзапуск этапу з вядомай точкі контролю, не падозрываючы прыхованы стан. Конфігурацыю трэба залічыць паза кодам прыемлі. Файлы сераўнавання, храненні секрэтных дадзеных і флагі функцияў павінны знаходзіцца ў адном месцы, якое аператары можаць пераглядаць, не чытаючы весь граф. Аддзельна трэба выдзеліць стварэнне кліента ад цыклу паведамленняў, каб можна было зменіць прадаўцоў без перапісвання машыны стану размовы. Для стадіі сімуляцыі дохадкаў портфеля неабходна перш чым зменяць код, апрацаваць параметры вхідных дадзеных, абярнучага этапу і крэтарыі выходу. Аператары должны магчымаць перзапуск этапу з вядомай точкі контролю, не падозрываючы прыхованы стан. Лепш выбіраць маленькія, тэставаныя елементы замест абмоўжлівых скрыптав. Калі этап не выканаецца, прычына неудачы павінна вказываць на адную адпаведальнасц, а не на кантэкст.

Спецыяльны пайплайн.

class VolatilityStrategyBacktester:
    def __init__(self, close_df: pd.DataFrame, high_df: pd.DataFrame, low_df: pd.DataFrame, volume_df: pd.DataFrame, benchmark: str):
        self.close_df = close_df
        self.high_df = high_df
        self.low_df = low_df
        self.volume_df = volume_df
        self.benchmark = benchmark
        self.asset_columns = [c for c in close_df.columns if c != benchmark]

    def backtest(self, params: dict) -> tuple[pd.Series, pd.Series]:
        lookback = int(params.get("lookback", 20))
        atr_mult = float(params.get("atr_multiplier", 2.0))
        vol_thresh = float(params.get("volume_threshold", 1.5))

        asset_returns_dict = {}

        for ticker in self.asset_columns:
            if ticker not in self.close_df.columns:
                continue
            c = self.close_df[ticker]
            h = self.high_df[ticker]
            l = self.low_df[ticker]
            v = self.volume_df[ticker]

            tr1 = h - l
            tr2 = (h - c.shift(1)).abs()
            tr3 = (l - c.shift(1)).abs()
            tr = pd.concat([tr1, tr2, tr3], axis=1).max(axis=1)
            atr = tr.rolling(window=lookback).mean()

            rolling_high = c.rolling(window=lookback).max()
            avg_vol = v.rolling(window=lookback).mean()

            breakout = (c > rolling_high.shift(1) + atr_mult *
                        atr) & (v > vol_thresh * avg_vol)

            asset_ret = c.pct_change()
            strat_ret = asset_ret * breakout.shift(1).fillna(False)

            trades = breakout & (~breakout.shift(1).fillna(False))
            strat_ret = strat_ret - (trades.astype(float) * 0.001)

            asset_returns_dict[ticker] = strat_ret

        strategy_df = pd.DataFrame(asset_returns_dict)
        portfolio_returns = strategy_df.mean(axis=1).fillna(0.0)
        benchmark_returns = self.close_df[self.benchmark].pct_change().fillna(
            0.0)

        return portfolio_returns, benchmark_returns
INFO - Baseline Metrics: Sharpe=-2.68, Return=-2.79%

Дзяржанне дизайну персонаў калькuluіцоў і цыкл дэбатаў

Кал працуеце над стадзіяй дизайну персонаў калькuluіцоў, спачатку запішыце контракт: неабходныя даннэ, сігнал успеху і тое, што выканаецца у разы частковага нявыпання. Такі чэк-ліст дапамагае заставіць пазнейшыя змены коду чыстымі. Спрыятлівае ставленне да гэтай стадзіі як да контракту межа даннемі і паверанымі выходамі. Дайце назву рэзультатам, задаце критэрыя успеху і адмовіцеся ад тыхоўскага частковага завершэння. Запісвайце ідэнтыфікатор запиту, ідэнтыфікатор моделі і час адпаведзення праз кожны вызов. Без гэтага логу періядычныя кантыненты прадастаўцоў выглядаюць як багі ў прыемніку.

Інжынерыяванне персонаў Gemini

Калі працюеце над стадзіяй «Engineering the Gemini Personas», спачатку запісайце угоду: неабяжлівыя даны, сігнал успеху і тое, што выходзіць у разе частковага неяксамоства. Такі список контроля дапамагае заліцьварыць пазнейшыя змены ў кодзе. Запісвайце часы выканання і кост токена або запиту праза функцыональнымі рэзультатамі. Відразуваяя візуабельнасць костаў запобегае неспакойным рахункам, калі процес пераходзіць з дэмаверсіі ў спяльныя среды. Запісвайце ID запиту, ID модэлю і час затрымкі праз кожны вызов. Без такога лёгасу періядычныя кантракты падаючых сервероў выглядаюць як багі ў прыемніку.

class Config:
    TICKERS = [
        "TSLA", "NVDA", "AMD", "PLTR", "COIN",
        "MARA", "RIOT", "MSTR", "HOOD", "ROKU",
        "UBER", "SHOP", "SNAP", "PTON", "DKNG"
    ]
    BENCHMARK = "SPY"
    MAX_ITERATIONS = 3
    INITIAL_PARAMS = {
        "lookback": 20,
        "atr_multiplier": 2.0,
        "volume_threshold": 1.5,
        "stop_loss_pct": 0.05
    }
class GeminiAgentPersona:
    def __init__(self, name: str, role: str, system_prompt: str):
        self.name = name
        self.role = role
        self.system_prompt = system_prompt
        self.client = genai.Client()

    def evaluate(self, current_params: dict, metrics: dict, iteration: int) -> dict:
        prompt = f"""
        You are {self.name}, a specialized {self.role} in a multi-agent quantitative trading system.
        Current Iteration: {iteration}
        Current Strategy Parameters: {json.dumps(current_params, indent=2)}
        Current Backtest Performance Metrics: {json.dumps(metrics, indent=2)}

        Analyze the performance and parameters from your professional perspective. Provide your critique and propose specific parameter adjustments (lookback, atr_multiplier, volume_threshold, stop_loss_pct) to improve the Sharpe ratio and reduce max drawdown.

        You MUST return a valid JSON object with keys:
        - "critique": Detailed analytical critique from your persona's perspective.
        - "proposed_adjustment": Dictionary of recommended parameter changes (e.g., ).
        - "confidence_score": Float between 0 and 1 representing your confidence in this adjustment.
        """

        response = self.client.models.generate_content(
            model="gemini-3.5-flash-lite",
            contents=prompt
        )

        text = response.text
        clean_text = text.strip()
        if clean_text.startswith("```json"):
            clean_text = clean_text[7:]
        if clean_text.endswith("```"):
            clean_text = clean_text[:-3]

        try:
            parsed = json.loads(clean_text.strip())
        except json.JSONDecodeError:
            parsed = {
                "critique": text[:500],
                "proposed_adjustment": current_params,
                "confidence_score": 0.6
            }
        return parsed

Аўтар: Коордынатар ітератыўных дэбатаў

Калі працуеце на стадыі координатора ітератывных дэбатаў, спачатку запісайце угоду: неабходныя даны, сігнал успеху і тое, што выканаецца у разы частковага нявыпалення. Такі список контроля дапамагае залічыць пазнейшыя змены ў кодзе чыстымі. Зберагаюце настройкі за межамі коду прыемліка. Файлы сераўіса, хранільнікі секрэтных данных і флагі функцыйяў должны знаходзіцца ў аднам месцы, куды аператары можаюць адбавіць аудыт без неабходнасці чытання всей структуры. Зявляйце логі з ідэнтыфікаторам запиту, ідэнтыфікаторам моделі і часам адзначэння кожнага вызову. Без такога следу періядычныя кантракты падрыхтавальніка выглядаюць як багі прыемліка. Калі працуеце на стадыі координатора ітератывных дэбатаў, спачатку запісайце угоду: неабходныя даны, сігнал успеху і тое, што выканаецца у разы частковага нявыпалення. Такі список контроля дапамагае залічыць пазнейшыя змены ў кодзе чыстымі. Валіце маленькія, тэставаныя елементы замест большых скрыптов. Калі якісь крок не выйшае, адказ за гэта нявыпалення должен вядомаць аб адной адпаведальнасці, а не пра заплутаны процес.

class PersonaDebateCoordinator:
    def __init__(self, backtester: VolatilityStrategyBacktester, initial_params: dict, max_iterations: int):
        self.backtester = backtester
        self.current_params = initial_params.copy()
        self.max_iterations = max_iterations

        self.quant = GeminiAgentPersona(
            "QuantAnalyst",
            "Quantitative Strategist",
            "Focuses on alpha generation, indicator sensitivity, and statistical edge."
        )
        self.risk = GeminiAgentPersona(
            "RiskManager",
            "Risk Officer",
            "Focuses on drawdowns, tail risk, position sizing, and volatility caps."
        )
        self.execution = GeminiAgentPersona(
            "ExecutionStrategist",
            "Execution Trading Specialist",
            "Focuses on liquidity, volume confirmation, slippage, and practical execution friction."
        )

        self.audit_log = []
        self.parameter_history = []

    def run_iterative_loop(self) -> dict:
        best_sharpe = -999.0
        consensus_rationale = "Initial baseline strategy evaluation."

        p_ret, b_ret = self.backtester.backtest(self.current_params)
        baseline_metrics = calculate_performance_metrics(p_ret, b_ret)
        current_metrics = baseline_metrics

        logging.info(
            f"Baseline Metrics: Sharpe={baseline_metrics['sharpe_ratio']:.2f}, Return={baseline_metrics['cumulative_return']*100:.2f}%")

        for i in range(1, self.max_iterations + 1):
            logging.debug(
                f"--- Starting Debate Iteration {i}/{self.max_iterations} ---")

            q_eval = self.quant.evaluate(
                self.current_params, current_metrics, i)
            r_eval = self.risk.evaluate(
                self.current_params, current_metrics, i)
            e_eval = self.execution.evaluate(
                self.current_params, current_metrics, i)

            for persona_name, eval_data in [("QuantAnalyst", q_eval), ("RiskManager", r_eval), ("ExecutionStrategist", e_eval)]:
                self.audit_log.append({
                    "iteration_number": i,
                    "persona_name": persona_name,
                    "critique_text": eval_data.get("critique", ""),
                    "proposed_adjustment": eval_data.get("proposed_adjustment", {}),
                    "confidence_score": eval_data.get("confidence_score", 0.8)
                })

            q_adj = q_eval.get("proposed_adjustment", {})
            r_adj = r_eval.get("proposed_adjustment", {})
            e_adj = e_eval.get("proposed_adjustment", {})

            new_lookback = int(np.mean([
                float(q_adj.get("lookback",
                      self.current_params["lookback"])),
                float(r_adj.get("lookback",
                      self.current_params["lookback"])),
                float(e_adj.get("lookback",
                      self.current_params["lookback"]))
            ]))
            new_atr = float(np.mean([
                float(q_adj.get("atr_multiplier",
                      self.current_params["atr_multiplier"])),
                float(r_adj.get("atr_multiplier",
                      self.current_params["atr_multiplier"])),
                float(e_adj.get("atr_multiplier",
                      self.current_params["atr_multiplier"]))
            ]))
            new_vol_thresh = float(np.mean([
                float(q_adj.get("volume_threshold",
                      self.current_params["volume_threshold"])),
                float(r_adj.get("volume_threshold",
                      self.current_params["volume_threshold"])),
                float(e_adj.get("volume_threshold",
                      self.current_params["volume_threshold"]))
            ]))
            new_sl = float(np.mean([
                float(q_adj.get("stop_loss_pct",
                      self.current_params["stop_loss_pct"])),
                float(r_adj.get("stop_loss_pct",
                      self.current_params["stop_loss_pct"])),
                float(e_adj.get("stop_loss_pct",
                      self.current_params["stop_loss_pct"]))
            ]))

            self.current_params = {
                "lookback": max(5, min(60, new_lookback)),
                "atr_multiplier": max(1.0, min(4.0, new_atr)),
                "volume_threshold": max(1.0, min(3.0, new_vol_thresh)),
                "stop_loss_pct": max(0.01, min(0.15, new_sl))
            }

            p_ret_new, b_ret_new = self.backtester.backtest(
                self.current_params)
            current_metrics = calculate_performance_metrics(
                p_ret_new, b_ret_new)

            logging.debug(
                f"Iteration {i} Results: Sharpe={current_metrics['sharpe_ratio']:.2f}, Return={current_metrics['cumulative_return']*100:.2f}%, Params={self.current_params}")

            self.parameter_history.append({
                "iteration": i,
                "params": self.current_params.copy(),
                "metrics": current_metrics.copy()
            })

            if current_metrics["sharpe_ratio"] > best_sharpe:
                best_sharpe = current_metrics["sharpe_ratio"]
                consensus_rationale = f"Iteration {i} consensus achieved superior Sharpe ratio through optimized ATR multiplier and volume threshold refinement."

        summary_result = {
            "strategy_version": "v2.0-optimized",
            "final_sharpe_ratio": float(best_sharpe),
            "consensus_rationale": consensus_rationale,
            "max_drawdown_delta": float(current_metrics["max_drawdown"] - baseline_metrics["max_drawdown"]),
            "total_iterations_run": self.max_iterations,
            "parameter_history": self.parameter_history
        }

        return summary_result
INFO - Successfully generated output JSON files.

Рэзультаты, аналіз працэйнасобности і параболкаванне

Методы, якія выкарыстоўваецца для аналізу рэзультатаў, працэйнасобности і апранавання, даходзяць да найкращых наслядкаў, калі іх рассматрываць як мерыябельныя показнікі. Перш чым расширваць масштабы, неабходна зафіксаваць адны ідеальны прыклад, адзін прыклад неудачы і запісы пра вярнэнне да пачатковага стану. Цей этап трэба рассматрываць як кантракт межу вхіднымі дадзеннямі і перакананымі выхіднымі рэзультатамі. Неабходна даць назвы всім элементам, задаць критэрыя успеху і не падзеўляцца частым, непазначаным частковым завершэнням задач. Перш чым выучаць працэўнасобность циклаў, трэба зафіксаваць версію інтэрпретара і файлы з інформацыяй пра залежнасці. Нестабільнасць пад час працы на ноутбуку і ў сервісах CI яўляецца найчастэйшай прычыной непазначаных абрываў у дэманстраціях API.

Квантыфікаўны аналіз ітерацый стратэгіі

Аварыя «Кантітатывны разбор стратэгіі» працюе наяўней, калі яе спрыяваць як мерыемую паверхню. Запісаце адна ідеальная транскрыпцыя, адзін прыклад неудачы і запіс пра вярнэнне да пачатковага стану перш чым расширваць масштаб. Запісвайце часы выконання і косты токеноў або запытаў разам з функцыйнаямі рэзультатамі. Відразлівасць костаў з самага пачатку запобегае неспакойным рахункам, калі процес пераходзіць з дэмавайнага режыма ў спяльныя среды. Закрепіце інтэрпретара і файл з правіламі залежнасцяў пры навучэнні циклу. Разлік межаў між ноутбукам і системай CI ёсць найчастэйшым таямным абар’язкам у дэмавайных прыкладах API.

def calculate_performance_metrics(portfolio_returns: pd.Series, benchmark_returns: pd.Series) -> dict:
    valid_idx = portfolio_returns.index.intersection(benchmark_returns.index)
    p_ret = portfolio_returns.loc[valid_idx]
    b_ret = benchmark_returns.loc[valid_idx]

    trading_days = 252
    cum_return = (1 + p_ret).prod() - 1
    annualized_return = (1 + cum_return) ** (trading_days /
                                             len(p_ret)) - 1 if len(p_ret) > 0 else 0.0
    annualized_vol = p_ret.std() * np.sqrt(trading_days)
    risk_free_rate = 0.03
    sharpe_ratio = (annualized_return - risk_free_rate) / \
        annualized_vol if annualized_vol > 0 else 0.0

    cum_wealth = (1 + p_ret).cumprod()
    peak = cum_wealth.cummax()
    drawdown = (cum_wealth - peak) / peak
    max_drawdown = drawdown.min()

    b_cum_return = (1 + b_ret).prod() - 1
    outperformance = cum_return - b_cum_return

    return {
        "cumulative_return": float(cum_return),
        "annualized_return": float(annualized_return),
        "annualized_volatility": float(annualized_vol),
        "sharpe_ratio": float(sharpe_ratio),
        "max_drawdown": float(max_drawdown),
        "benchmark_cumulative_return": float(b_cum_return),
        "outperformance": float(outperformance)
    }
{
    "strategy_version": "v2.0-optimized",
    "final_sharpe_ratio": -0.6822300207528283,
    "consensus_rationale": "Iteration 1 consensus achieved superior Sharpe ratio through optimized ATR multiplier and volume threshold refinement.",
    "parameter_history": [
        {
            "iteration": 1,
            "params": {
                "lookback": 14,
                "atr_multiplier": 1.5,
                "volume_threshold": 1.4666,
                "stop_loss_pct": 0.025
            },
            "metrics": {
                "cumulative_return": 0.0399,
                "annualized_return": 0.0132,
                "sharpe_ratio": -0.6822,
                "max_drawdown": -0.0344
            }
        }
    ]
}

Рэальнасці бенчмаркаў і візуалізацыя стратэгій

Аварыс «Benchmark Realities and Strategy» працюе наяўней, калі яго спрыяваць як мерыемую паверхню. Зберагуце адны ідеальны прыклад роботы, адзін прыклад неудачы і запіс пра вярнэнне да пачатковага стану перш чым расширваце сферу дзейнасці. Хавайце настройкі за межамі коду прыемлівання. Файлы сераўнавальной среды, хранільнікі секрэтных дадзеных і флагі функцыйяў должны знаходзіцца ў аднам месцы, куды аператары можаць адбавляць контроль без неабяжнага чытання всіх дадзеных. Закрепіце інтэрпретара і файлы з інформацыяй пра залежнасці перш чым выкладзіце інструкціі па виконанню цыклу. Разлікы межаў лептапа і системы CI ёсць найчастэйшай прычыной тых, чаму дэманстраціі API не працуюць. Аварыс «Benchmark Realities and Strategy» працюе наяўней, калі яго спрыяваць як мерыемую паверхню. Зберагуце адны ідеальны прыклад роботы, адзін прыклад неудачы і запіс пра вярнэнне да пачатковага стану перш чым расширваце сферу дзейнасці. Валіце маленькія, тэставаныя елементы замест большых скрыптов. Калі якісь крок не выйшае, неудача должна вказываць на адну конкрэтную адпаведальнасць, а не на заплутаны ланцоўкі дзеянасцей.

def main():
    logging.info(
        "Starting Multi-Agent Volatility Breakout Optimization Pipeline.")

    loader = MarketDataLoader(Config.TICKERS, Config.BENCHMARK)
    close_df, high_df, low_df, volume_df = loader.fetch_data()

    backtester = VolatilityStrategyBacktester(
        close_df, high_df, low_df, volume_df, Config.BENCHMARK)

    # Run initial baseline backtest
    baseline_p_ret, baseline_b_ret = backtester.backtest(Config.INITIAL_PARAMS)

    coordinator = PersonaDebateCoordinator(
        backtester, Config.INITIAL_PARAMS, Config.MAX_ITERATIONS)
    summary_results = coordinator.run_iterative_loop()

    # Write output files exactly as specified
    with open("volatility_debate_summary.json", "w") as f:
        json.dump(summary_results, f, indent=4)

    with open("iteration_debate_audit_log.json", "w") as f:
        json.dump(coordinator.audit_log, f, indent=4)

    logging.info("Successfully generated output JSON files.")

    # Generate annotated plot
    fig, ax = plt.subplots(figsize=(10, 6))
    optimized_p_ret, _ = backtester.backtest(coordinator.current_params)

    wealth_baseline = (1 + baseline_p_ret).cumprod()
    wealth_optimized = (1 + optimized_p_ret).cumprod()
    wealth_benchmark = (1 + baseline_b_ret).cumprod()

    ax.plot(wealth_baseline.index, wealth_baseline,
            label="Baseline Strategy", color="gray", linestyle="--")
    ax.plot(wealth_optimized.index, wealth_optimized,
            label="Optimized Multi-Agent Strategy", color="blue", linewidth=2)
    ax.plot(wealth_benchmark.index, wealth_benchmark,
            label="SPY Benchmark", color="orange", alpha=0.7)

    # Annotate final peak / convergence
    max_idx = wealth_optimized.idxmax()
    max_val = wealth_optimized.max()
    ax.annotate(f"Optimized Peak: {max_val:.2f}x",
                xy=(max_idx, max_val),
                xytext=(max_idx - pd.Timedelta(days=90), max_val * 0.9),
                arrowprops=dict(facecolor='blue', shrink=0.05, width=1, headwidth=6))

    ax.set_title("Multi-Agent Volatility Breakout Portfolio vs. SPY Benchmark",
                 fontsize=12, fontweight='bold')
    ax.set_xlabel("Date", fontsize=10)
    ax.set_ylabel("Growth of 1.00", fontsize=10)
    ax.legend(loc="upper left")
    ax.grid(True, linestyle=":", alpha=0.6)

    plt.tight_layout()
    plt.show()
    logging.info("Successfully generated strategy performance plot.")
if __name__ == "__main__":
    main()
INFO - Successfully generated strategy performance plot.

Заключэнне і наступныя крокі ў процесе стварэння

У фазе заключэння і наступных крокаў стварэння неабходна практычна вызначыць вхідныя даны, адпаведальную особу за выкананне кроку і критэрыя завершэння пры перамены коду. Аператары должны магчымае запускіць крок з вядомай точкі контролю, не спрабоўваючы здогадвацца пра схованы стан. Цю фазу трэба розглядаць як кантракт межа вхіднымі данымі і перакананымі выходнымі рэзультатамі. Назваць всі ствароўваны элементы, практычна вызначыць критэрыя успеху і не падтрымліваць бяспечнае частковае завершэння задання. Аддзельна выделяць процес стварэння кліента ад циклу обмену паведамленнямі, ўжо бы адпаведальныя стороны маглі зменяцца без перапісвання машыны стану дыялогу.

Чэрніця для аператыўных задач

У фазе чэрніцы для аператыўных задач неабходна практычна вызначыць вхідныя даны, адпаведальную особу за выкананне кроку і критэрыя завершэння пры перамены коду. Аператары должны магчымае запускіць крок з вядомай точкі контролю, не спрабоўваючы здагадвацца пра схованы стан.

Запісвайце адно і шлях успеху, і шлях вярнення. Перапрыткі, людзкія контраліны і обработка некоректных паведамленняў ёсць часткаю продукту, а не чымсь, што дадаецца пазней.

Аддзельце стварэнне кліента ад цыклу паведамленняў, ўпэўніваючыся, што прадаўцы можна будзе заменіць без перапісвання машыны стана размовы.

Зробіце контрольны пункт пасля дорогіх крокаў. Система вярнення не павінна знову ставіць плату за той самы вызов LLM, калі аператар перапрыткае пазнейшы вузел.

Фіксуйце версіі залежнасцяў і запісвайце хэш адпаведнага зображэння, якое было выкарыстоўвана для дэманстрацыі. Возможнасць павтарнага стварэння ситуацыі лепшая, чым традыцыйныя знання.

Запісвайце часы выканення і кост токенаў або запытаў разам з функцыйнальнымі рэзултатамі. Відразувая інформацыю пра косты запобегае неспакойным рахункам, калі процес пераходзіць з дэманстрацыі ў спяльныя сераўеры.

Перш чым запускать стак, заморозьце версіі, зафіксавце «золаты» транскрыпты для критычнага шляху і паказвце спосабы атрыбутавання. У спільных сэрвісах неабходны ліміты частоты запытоў, пераканання ў належнасці тэнантам і чысткі власнік для ротацыі секрэтных даных. Лепш выбіраць простую надзею на надзейнасць, чым хітрыя експерыментальныя дэманстрацыі.

Прыметкі для 476dcdb15114: не кладзіце ключы прадастоўчыка ў репазітарый, задаце верхнюю межу токена на кожную сесію і зберагачыце транскрыпты празаўсёды з фікстурамі eval, каб пазнейшыя замены модэляў заставаліся порównаннімы.