Update GPT settings for gpt-5.5
This commit is contained in:
@@ -108,6 +108,8 @@ When no prefix is provided, such as manual Python execution, Python keeps using
|
|||||||
- Running marker: `<prefix>_process_running_entry.txt`
|
- Running marker: `<prefix>_process_running_entry.txt`
|
||||||
- Batch file: `<TerminalDataPath>\MQL5\python_for_ea\bat\get_entry_reply.bat`
|
- Batch file: `<TerminalDataPath>\MQL5\python_for_ea\bat\get_entry_reply.bat`
|
||||||
|
|
||||||
|
H1 candidate generation uses the OpenAI Responses API. The default model is `gpt-5.5`, the default `reasoning.effort` is `low`, and the default `text.verbosity` is `low`. `temperature` is not set. Runtime overrides are available through `OPENAI_MODEL`, `OPENAI_REASONING_EFFORT`, and `OPENAI_TEXT_VERBOSITY`. Output is validated with `text.format` Structured Outputs JSON Schema; incomplete responses, schema mismatches, price-rule failures, and insufficient reward/risk fall back to safe-stop values.
|
||||||
|
|
||||||
During `OnInit()`, the EA resolves `MQL5\python_for_ea` from `TerminalInfoString(TERMINAL_DATA_PATH)` and builds absolute batch-file paths. Each batch file resolves the Python project root from its own location, so runtime execution no longer depends on `C:\ea_py`.
|
During `OnInit()`, the EA resolves `MQL5\python_for_ea` from `TerminalInfoString(TERMINAL_DATA_PATH)` and builds absolute batch-file paths. Each batch file resolves the Python project root from its own location, so runtime execution no longer depends on `C:\ea_py`.
|
||||||
|
|
||||||
`target_prices.txt` must contain 13 lines:
|
`target_prices.txt` must contain 13 lines:
|
||||||
@@ -219,6 +221,7 @@ After an H4 `market_state` reload, the EA cancels existing pending orders whose
|
|||||||
|
|
||||||
### 2026-06-06
|
### 2026-06-06
|
||||||
|
|
||||||
|
- Updated the Python-side OpenAI default model to the official `gpt-5.5` slug and made Responses API calls send explicit `reasoning.effort` and `text.verbosity`. For GPT-5.5, the output contract is now documented as primarily enforced by Structured Outputs rather than duplicated prompt schema text.
|
||||||
- Added compatibility declarations to `HIT-EA_refactor_ver5.mq5` so it compiles against the current shared headers, covering split-entry zones, Python linkage filenames, and pending-cancel retry tracking. Since `use_split_entry_zone = false` by default, the normal ver5 entry behavior remains unchanged.
|
- Added compatibility declarations to `HIT-EA_refactor_ver5.mq5` so it compiles against the current shared headers, covering split-entry zones, Python linkage filenames, and pending-cancel retry tracking. Since `use_split_entry_zone = false` by default, the normal ver5 entry behavior remains unchanged.
|
||||||
|
|
||||||
### 2026-06-01
|
### 2026-06-01
|
||||||
|
|||||||
@@ -108,6 +108,8 @@ EAは `OnInit()` で `_Symbol` と `magic_number` から `HIT_<sanitized symbol>
|
|||||||
- 実行中フラグ: `<prefix>_process_running_entry.txt`
|
- 実行中フラグ: `<prefix>_process_running_entry.txt`
|
||||||
- 起動バッチ: `<TerminalDataPath>\MQL5\python_for_ea\bat\get_entry_reply.bat`
|
- 起動バッチ: `<TerminalDataPath>\MQL5\python_for_ea\bat\get_entry_reply.bat`
|
||||||
|
|
||||||
|
H1候補生成はOpenAI Responses APIを使用する。既定モデルは `gpt-5.5`、既定 `reasoning.effort` は `low`、既定 `text.verbosity` は `low` とする。`temperature` は指定せず、`OPENAI_MODEL`、`OPENAI_REASONING_EFFORT`、`OPENAI_TEXT_VERBOSITY` で実行時上書きできる。出力は `text.format` のStructured Outputs JSON Schemaで検証し、未完了応答、schema不一致、価格条件違反、reward/risk不足は安全側停止値へ倒す。
|
||||||
|
|
||||||
EAは `OnInit()` で `TerminalInfoString(TERMINAL_DATA_PATH)` から `MQL5\python_for_ea` を解決し、各batファイルの絶対パスを組み立てる。batファイルは自身の位置からPythonプロジェクトルートを解決するため、`C:\ea_py` には依存しない。
|
EAは `OnInit()` で `TerminalInfoString(TERMINAL_DATA_PATH)` から `MQL5\python_for_ea` を解決し、各batファイルの絶対パスを組み立てる。batファイルは自身の位置からPythonプロジェクトルートを解決するため、`C:\ea_py` には依存しない。
|
||||||
|
|
||||||
`target_prices.txt` は13行構成とする。
|
`target_prices.txt` は13行構成とする。
|
||||||
@@ -219,6 +221,7 @@ H4 `market_state` の再読込後は、更新後の状態で許可されない
|
|||||||
|
|
||||||
### 2026-06-06
|
### 2026-06-06
|
||||||
|
|
||||||
|
- Python側のOpenAI既定モデルを公式slugの `gpt-5.5` へ更新し、Responses API呼び出しで `reasoning.effort` と `text.verbosity` を明示する仕様にした。GPT-5.5向けに、出力形式はプロンプト重複指定ではなくStructured Outputsを主契約として扱う。
|
||||||
- `HIT-EA_refactor_ver5.mq5` が現行の共有ヘッダーを使用してもコンパイルできるよう、split-entry zone、Python連携ファイル名、pending取消リトライ管理に必要な互換宣言を追加した。既定では `use_split_entry_zone = false` のため、ver5の通常エントリー挙動は維持する。
|
- `HIT-EA_refactor_ver5.mq5` が現行の共有ヘッダーを使用してもコンパイルできるよう、split-entry zone、Python連携ファイル名、pending取消リトライ管理に必要な互換宣言を追加した。既定では `use_split_entry_zone = false` のため、ver5の通常エントリー挙動は維持する。
|
||||||
|
|
||||||
### 2026-06-01
|
### 2026-06-01
|
||||||
|
|||||||
@@ -133,7 +133,9 @@ EA側で分割エントリーを有効にした場合は、この予測ゾーン
|
|||||||
## OpenAI 設定
|
## OpenAI 設定
|
||||||
|
|
||||||
H1 エントリー候補生成では OpenAI API を使用します。
|
H1 エントリー候補生成では OpenAI API を使用します。
|
||||||
Responses APIの `text.format` にJSON Schemaを渡し、GPT出力を自然文やCSV風テキストではなく
|
既定モデルは `gpt-5.5` です。Responses APIへ `reasoning.effort` と
|
||||||
|
`text.verbosity` を明示して送り、`temperature` は使用しません。
|
||||||
|
`text.format` にはJSON Schemaを渡し、GPT出力を自然文やCSV風テキストではなく
|
||||||
`schema_version` と `strategies` を持つ構造化JSONに固定します。
|
`schema_version` と `strategies` を持つ構造化JSONに固定します。
|
||||||
JSONが不正、API応答が未完了、価格条件やreward/risk条件に合わない場合は停止値へ倒します。
|
JSONが不正、API応答が未完了、価格条件やreward/risk条件に合わない場合は停止値へ倒します。
|
||||||
|
|
||||||
@@ -146,13 +148,14 @@ $env:OPENAI_API_KEY = "..."
|
|||||||
任意:
|
任意:
|
||||||
|
|
||||||
```powershell
|
```powershell
|
||||||
$env:OPENAI_MODEL = "..."
|
$env:OPENAI_MODEL = "gpt-5.5"
|
||||||
$env:OPENAI_REASONING_EFFORT = "low"
|
$env:OPENAI_REASONING_EFFORT = "low"
|
||||||
|
$env:OPENAI_TEXT_VERBOSITY = "low"
|
||||||
$env:MT5_EA_FILE_PREFIX = "HIT_GOLD_10001"
|
$env:MT5_EA_FILE_PREFIX = "HIT_GOLD_10001"
|
||||||
$env:MT5_PRICE_DIGITS = "2"
|
$env:MT5_PRICE_DIGITS = "2"
|
||||||
```
|
```
|
||||||
|
|
||||||
`OPENAI_MODEL` 未設定時は `src/ea_py/constants.py` の `DEFAULT_GPT_MODEL` を使います。`OPENAI_REASONING_EFFORT` は `none`, `low`, `medium`, `high`, `xhigh` のいずれかです。`MT5_EA_FILE_PREFIX` と `MT5_PRICE_DIGITS` は手動実行時だけ指定すればよく、EA/bat経由では自動設定されます。
|
`OPENAI_MODEL` 未設定時は `src/ea_py/constants.py` の `DEFAULT_GPT_MODEL` を使います。`OPENAI_REASONING_EFFORT` は `none`, `low`, `medium`, `high`, `xhigh` のいずれかです。H1候補生成の既定は低遅延と再現性確認のため `low` ですが、品質優先の検証では `medium` も評価してください。`OPENAI_TEXT_VERBOSITY` は `low`, `medium`, `high` のいずれかで、既定はJSON専用応答に合わせて `low` です。`MT5_EA_FILE_PREFIX` と `MT5_PRICE_DIGITS` は手動実行時だけ指定すればよく、EA/bat経由では自動設定されます。
|
||||||
|
|
||||||
## 主なモジュール
|
## 主なモジュール
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
このドキュメントは、MT5データフォルダ配下の `MQL5\python_for_ea` のフォルダ構成に関する正本である。
|
このドキュメントは、MT5データフォルダ配下の `MQL5\python_for_ea` のフォルダ構成に関する正本である。
|
||||||
|
|
||||||
現在のプロジェクトは、MT5 HIT-EAから出力されたOHLC CSVをPythonで解析し、OpenAI APIを使ってGOLD/XAUUSD向けの相場環境とエントリー候補価格を返す補助アプリケーションである。
|
現在のプロジェクトは、MT5 HIT-EAから出力されたOHLC CSVをPythonで解析し、GOLD/XAUUSD向けのH4相場環境とH1エントリー候補価格を返す補助アプリケーションである。H4相場環境はルールベースで判定し、H1エントリー候補価格のみOpenAI APIを使う。
|
||||||
|
|
||||||
MT5 EAから `bat/` 経由でルート直下のPythonスクリプトが呼ばれているため、現時点ではルート直下の `get_trend_reply.py` と `get_entry_reply.py` を実行入口として維持する。
|
MT5 EAから `bat/` 経由でルート直下のPythonスクリプトが呼ばれているため、現時点ではルート直下の `get_trend_reply.py` と `get_entry_reply.py` を実行入口として維持する。
|
||||||
|
|
||||||
@@ -197,7 +197,7 @@ EAファイルはこのPythonプロジェクトの外部連携先として扱う
|
|||||||
|
|
||||||
| モジュール | 責務 |
|
| モジュール | 責務 |
|
||||||
|---|---|
|
|---|---|
|
||||||
| `src/ea_py/config.py` | 環境変数、モデル名、デバッグ設定などの設定読み込み。 |
|
| `src/ea_py/config.py` | 環境変数、GPT-5.5モデル名、reasoning effort、text verbosity、デバッグ設定などの設定読み込み。 |
|
||||||
| `src/ea_py/paths.py` | MT5データフォルダ、入力CSV、出力ファイルパスの組み立て。 |
|
| `src/ea_py/paths.py` | MT5データフォルダ、入力CSV、出力ファイルパスの組み立て。 |
|
||||||
| `src/ea_py/constants.py` | `market_state`、ATR期間、出力サイズなどの定数。 |
|
| `src/ea_py/constants.py` | `market_state`、ATR期間、出力サイズなどの定数。 |
|
||||||
| `src/ea_py/types.py` | OHLCバー、OHLC要約、13行出力などの型定義。 |
|
| `src/ea_py/types.py` | OHLCバー、OHLC要約、13行出力などの型定義。 |
|
||||||
@@ -212,7 +212,7 @@ EAファイルはこのPythonプロジェクトの外部連携先として扱う
|
|||||||
| `src/ea_py/market/imbalance.py` | H1インバランス初動判定。 |
|
| `src/ea_py/market/imbalance.py` | H1インバランス初動判定。 |
|
||||||
| `src/ea_py/prompts/trend_prompt.py` | H4相場環境判定プロンプトの生成。 |
|
| `src/ea_py/prompts/trend_prompt.py` | H4相場環境判定プロンプトの生成。 |
|
||||||
| `src/ea_py/prompts/entry_prompt.py` | H1候補価格生成プロンプトの生成。 |
|
| `src/ea_py/prompts/entry_prompt.py` | H1候補価格生成プロンプトの生成。 |
|
||||||
| `src/ea_py/openai_client.py` | OpenAI API呼び出しの薄いラッパー。 |
|
| `src/ea_py/openai_client.py` | GPT-5.5向けのResponses API呼び出し、reasoning/text設定、Structured Outputs指定をまとめる薄いラッパー。 |
|
||||||
| `src/ea_py/pipelines/trend_pipeline.py` | H4判定処理全体のオーケストレーション。 |
|
| `src/ea_py/pipelines/trend_pipeline.py` | H4判定処理全体のオーケストレーション。 |
|
||||||
| `src/ea_py/pipelines/entry_pipeline.py` | H1候補生成処理全体のオーケストレーション。 |
|
| `src/ea_py/pipelines/entry_pipeline.py` | H1候補生成処理全体のオーケストレーション。 |
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,14 @@ from __future__ import annotations
|
|||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
import os
|
import os
|
||||||
|
|
||||||
from ea_py.constants import DEBUG_PRINT, DEFAULT_GPT_MODEL, DEFAULT_REASONING_EFFORT, VALID_REASONING_EFFORTS
|
from ea_py.constants import (
|
||||||
|
DEBUG_PRINT,
|
||||||
|
DEFAULT_GPT_MODEL,
|
||||||
|
DEFAULT_REASONING_EFFORT,
|
||||||
|
DEFAULT_TEXT_VERBOSITY,
|
||||||
|
VALID_REASONING_EFFORTS,
|
||||||
|
VALID_TEXT_VERBOSITIES,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@dataclass(frozen=True)
|
@dataclass(frozen=True)
|
||||||
@@ -15,6 +22,7 @@ class RuntimeConfig:
|
|||||||
api_key: str
|
api_key: str
|
||||||
model: str
|
model: str
|
||||||
reasoning_effort: str
|
reasoning_effort: str
|
||||||
|
text_verbosity: str
|
||||||
debug_print: bool
|
debug_print: bool
|
||||||
|
|
||||||
|
|
||||||
@@ -22,6 +30,7 @@ def load_runtime_config(
|
|||||||
*,
|
*,
|
||||||
model: str | None = None,
|
model: str | None = None,
|
||||||
reasoning_effort: str | None = None,
|
reasoning_effort: str | None = None,
|
||||||
|
text_verbosity: str | None = None,
|
||||||
debug_print: bool = DEBUG_PRINT,
|
debug_print: bool = DEBUG_PRINT,
|
||||||
) -> RuntimeConfig:
|
) -> RuntimeConfig:
|
||||||
"""OpenAI呼び出しに必要な実行時設定を読み込む。
|
"""OpenAI呼び出しに必要な実行時設定を読み込む。
|
||||||
@@ -30,9 +39,9 @@ def load_runtime_config(
|
|||||||
`OPENAI_API_KEY` 環境変数からのみ取得する。
|
`OPENAI_API_KEY` 環境変数からのみ取得する。
|
||||||
未設定の場合は `RuntimeError` を送出し、上位パイプラインで停止値を出力する。
|
未設定の場合は `RuntimeError` を送出し、上位パイプラインで停止値を出力する。
|
||||||
|
|
||||||
`model` / `reasoning_effort` / `debug_print` は呼び出し側から上書き可能だが、
|
`model` / `reasoning_effort` / `text_verbosity` / `debug_print` は呼び出し側から上書き可能だが、
|
||||||
通常は `constants.py` のデフォルト値を使う。
|
通常は `constants.py` のデフォルト値を使う。
|
||||||
`OPENAI_MODEL` と `OPENAI_REASONING_EFFORT` が設定されている場合は、
|
`OPENAI_MODEL` / `OPENAI_REASONING_EFFORT` / `OPENAI_TEXT_VERBOSITY` が設定されている場合は、
|
||||||
引数未指定時の実行時上書きとして扱う。
|
引数未指定時の実行時上書きとして扱う。
|
||||||
"""
|
"""
|
||||||
api_key = os.getenv("OPENAI_API_KEY")
|
api_key = os.getenv("OPENAI_API_KEY")
|
||||||
@@ -41,16 +50,24 @@ def load_runtime_config(
|
|||||||
|
|
||||||
selected_model = model or os.getenv("OPENAI_MODEL") or DEFAULT_GPT_MODEL
|
selected_model = model or os.getenv("OPENAI_MODEL") or DEFAULT_GPT_MODEL
|
||||||
selected_reasoning_effort = reasoning_effort or os.getenv("OPENAI_REASONING_EFFORT") or DEFAULT_REASONING_EFFORT
|
selected_reasoning_effort = reasoning_effort or os.getenv("OPENAI_REASONING_EFFORT") or DEFAULT_REASONING_EFFORT
|
||||||
|
selected_text_verbosity = text_verbosity or os.getenv("OPENAI_TEXT_VERBOSITY") or DEFAULT_TEXT_VERBOSITY
|
||||||
if selected_reasoning_effort not in VALID_REASONING_EFFORTS:
|
if selected_reasoning_effort not in VALID_REASONING_EFFORTS:
|
||||||
allowed = ", ".join(sorted(VALID_REASONING_EFFORTS))
|
allowed = ", ".join(sorted(VALID_REASONING_EFFORTS))
|
||||||
raise RuntimeError(
|
raise RuntimeError(
|
||||||
f"OPENAI_REASONING_EFFORT が不正です: {selected_reasoning_effort!r}. "
|
f"OPENAI_REASONING_EFFORT が不正です: {selected_reasoning_effort!r}. "
|
||||||
f"allowed={allowed}"
|
f"allowed={allowed}"
|
||||||
)
|
)
|
||||||
|
if selected_text_verbosity not in VALID_TEXT_VERBOSITIES:
|
||||||
|
allowed = ", ".join(sorted(VALID_TEXT_VERBOSITIES))
|
||||||
|
raise RuntimeError(
|
||||||
|
f"OPENAI_TEXT_VERBOSITY が不正です: {selected_text_verbosity!r}. "
|
||||||
|
f"allowed={allowed}"
|
||||||
|
)
|
||||||
|
|
||||||
return RuntimeConfig(
|
return RuntimeConfig(
|
||||||
api_key=api_key,
|
api_key=api_key,
|
||||||
model=selected_model,
|
model=selected_model,
|
||||||
reasoning_effort=selected_reasoning_effort,
|
reasoning_effort=selected_reasoning_effort,
|
||||||
|
text_verbosity=selected_text_verbosity,
|
||||||
debug_print=debug_print,
|
debug_print=debug_print,
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -4,9 +4,11 @@ from __future__ import annotations
|
|||||||
|
|
||||||
MT_ENCODING = "utf-16 LE"
|
MT_ENCODING = "utf-16 LE"
|
||||||
|
|
||||||
DEFAULT_GPT_MODEL = "gpt-5.5-2026-04-23"
|
DEFAULT_GPT_MODEL = "gpt-5.5"
|
||||||
DEFAULT_REASONING_EFFORT = "low"
|
DEFAULT_REASONING_EFFORT = "low"
|
||||||
VALID_REASONING_EFFORTS = frozenset({"none", "low", "medium", "high", "xhigh"})
|
VALID_REASONING_EFFORTS = frozenset({"none", "low", "medium", "high", "xhigh"})
|
||||||
|
DEFAULT_TEXT_VERBOSITY = "low"
|
||||||
|
VALID_TEXT_VERBOSITIES = frozenset({"low", "medium", "high"})
|
||||||
DEBUG_PRINT = True
|
DEBUG_PRINT = True
|
||||||
ENTRY_RESPONSE_SCHEMA_VERSION = 1
|
ENTRY_RESPONSE_SCHEMA_VERSION = 1
|
||||||
|
|
||||||
|
|||||||
@@ -60,6 +60,7 @@ def append_debug_entry(
|
|||||||
path: Path,
|
path: Path,
|
||||||
model: str,
|
model: str,
|
||||||
reasoning_effort: str,
|
reasoning_effort: str,
|
||||||
|
text_verbosity: str,
|
||||||
max_output_tokens: int,
|
max_output_tokens: int,
|
||||||
api_diagnostics: str,
|
api_diagnostics: str,
|
||||||
timeframe: str,
|
timeframe: str,
|
||||||
@@ -79,6 +80,7 @@ def append_debug_entry(
|
|||||||
file.write(f"DEBUG TIME : {now_str()}\n")
|
file.write(f"DEBUG TIME : {now_str()}\n")
|
||||||
file.write(f"MODEL : {model}\n")
|
file.write(f"MODEL : {model}\n")
|
||||||
file.write(f"REASONING : {reasoning_effort}\n")
|
file.write(f"REASONING : {reasoning_effort}\n")
|
||||||
|
file.write(f"VERBOSITY : {text_verbosity}\n")
|
||||||
file.write(f"MAX TOKENS : {max_output_tokens}\n")
|
file.write(f"MAX TOKENS : {max_output_tokens}\n")
|
||||||
file.write(f"TIMEFRAME : {timeframe}\n")
|
file.write(f"TIMEFRAME : {timeframe}\n")
|
||||||
file.write(f"MARKET_STATE(H4) : {trend_state} ({MARKET_STATE_LABELS.get(trend_state, 'UNKNOWN')})\n")
|
file.write(f"MARKET_STATE(H4) : {trend_state} ({MARKET_STATE_LABELS.get(trend_state, 'UNKNOWN')})\n")
|
||||||
|
|||||||
@@ -94,6 +94,7 @@ def call_responses_api(
|
|||||||
image_data_urls: Sequence[str],
|
image_data_urls: Sequence[str],
|
||||||
max_output_tokens: int,
|
max_output_tokens: int,
|
||||||
response_text_format: Mapping[str, Any] | None = None,
|
response_text_format: Mapping[str, Any] | None = None,
|
||||||
|
text_verbosity: str | None = None,
|
||||||
) -> ResponsesApiResult:
|
) -> ResponsesApiResult:
|
||||||
"""Responses APIへテキストとチャート画像を送り、出力テキストを返す。
|
"""Responses APIへテキストとチャート画像を送り、出力テキストを返す。
|
||||||
|
|
||||||
@@ -103,6 +104,7 @@ def call_responses_api(
|
|||||||
|
|
||||||
`response_text_format` が指定された場合は Responses API の `text.format` へ渡し、
|
`response_text_format` が指定された場合は Responses API の `text.format` へ渡し、
|
||||||
JSON Schemaなどの構造化出力をAPI側でも強制する。
|
JSON Schemaなどの構造化出力をAPI側でも強制する。
|
||||||
|
`text_verbosity` はGPT-5.5の最終出力長を制御し、reasoning品質とは独立して扱う。
|
||||||
|
|
||||||
戻り値は `response.output_text` をstripした文字列とAPI診断情報。
|
戻り値は `response.output_text` をstripした文字列とAPI診断情報。
|
||||||
API例外や空/不正な出力の安全側処理は、この薄いラッパーではなく
|
API例外や空/不正な出力の安全側処理は、この薄いラッパーではなく
|
||||||
@@ -129,8 +131,13 @@ def call_responses_api(
|
|||||||
"reasoning": {"effort": reasoning_effort},
|
"reasoning": {"effort": reasoning_effort},
|
||||||
"max_output_tokens": max_output_tokens,
|
"max_output_tokens": max_output_tokens,
|
||||||
}
|
}
|
||||||
|
text_config: dict[str, Any] = {}
|
||||||
if response_text_format is not None:
|
if response_text_format is not None:
|
||||||
create_params["text"] = {"format": dict(response_text_format)}
|
text_config["format"] = dict(response_text_format)
|
||||||
|
if text_verbosity is not None:
|
||||||
|
text_config["verbosity"] = text_verbosity
|
||||||
|
if text_config:
|
||||||
|
create_params["text"] = text_config
|
||||||
|
|
||||||
response = client.responses.create(**create_params)
|
response = client.responses.create(**create_params)
|
||||||
diagnostics = _extract_response_diagnostics(response)
|
diagnostics = _extract_response_diagnostics(response)
|
||||||
|
|||||||
@@ -323,6 +323,7 @@ def run_pipeline() -> None:
|
|||||||
image_data_urls=images_data_urls,
|
image_data_urls=images_data_urls,
|
||||||
max_output_tokens=max_tokens,
|
max_output_tokens=max_tokens,
|
||||||
response_text_format=response_text_format,
|
response_text_format=response_text_format,
|
||||||
|
text_verbosity=config.text_verbosity,
|
||||||
)
|
)
|
||||||
gpt_reply = gpt_result.text
|
gpt_reply = gpt_result.text
|
||||||
api_diagnostics = gpt_result.diagnostics.to_log_text()
|
api_diagnostics = gpt_result.diagnostics.to_log_text()
|
||||||
@@ -378,6 +379,7 @@ def run_pipeline() -> None:
|
|||||||
path=paths.debug_reason,
|
path=paths.debug_reason,
|
||||||
model=config.model,
|
model=config.model,
|
||||||
reasoning_effort=config.reasoning_effort,
|
reasoning_effort=config.reasoning_effort,
|
||||||
|
text_verbosity=config.text_verbosity,
|
||||||
max_output_tokens=max_tokens,
|
max_output_tokens=max_tokens,
|
||||||
api_diagnostics=api_diagnostics,
|
api_diagnostics=api_diagnostics,
|
||||||
timeframe=ENTRY_TIMEFRAME,
|
timeframe=ENTRY_TIMEFRAME,
|
||||||
|
|||||||
@@ -320,13 +320,11 @@ def build_common_rules_block(
|
|||||||
- エントリー後12時間以内に利確・損切に到達しなければ、その時点の価格でクローズ。
|
- エントリー後12時間以内に利確・損切に到達しなければ、その時点の価格でクローズ。
|
||||||
|
|
||||||
【出力ルール(最重要)】
|
【出力ルール(最重要)】
|
||||||
- Responses APIのJSON Schemaに一致するJSONオブジェクトだけを出力してください。
|
- Responses APIのStructured Outputs(JSON Schema)で検証されるJSONオブジェクトだけを出力してください。
|
||||||
- schema_version は {ENTRY_RESPONSE_SCHEMA_VERSION}。
|
- schema_version は {ENTRY_RESPONSE_SCHEMA_VERSION}。
|
||||||
- strategies には対象戦略だけを入れ、順序は {out_order}。
|
- strategies には対象戦略だけを入れ、順序は {out_order}。
|
||||||
- 各strategy要素は strategy, decision, entry, tp, sl, zone_low, zone_high, reason_code を必ず含めてください。
|
- decision は "use" または "skip"、reason_code は次のいずれかのみ: {", ".join(ENTRY_REASON_CODES)}
|
||||||
- decision は "use" または "skip" のみ。
|
- 自然文、Markdown、空行は一切出力しないでください。
|
||||||
- reason_code は次のいずれかのみ: {", ".join(ENTRY_REASON_CODES)}
|
|
||||||
- 自然文、Markdown、余分なキー、空行は一切出力しないでください。
|
|
||||||
""".strip()
|
""".strip()
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -7,17 +7,33 @@ import pytest
|
|||||||
from ea_py.config import load_runtime_config
|
from ea_py.config import load_runtime_config
|
||||||
|
|
||||||
|
|
||||||
|
def test_load_runtime_config_uses_gpt55_defaults(monkeypatch: pytest.MonkeyPatch) -> None:
|
||||||
|
"""Default OpenAI settings follow the GPT-5.5 Responses API contract."""
|
||||||
|
monkeypatch.setenv("OPENAI_API_KEY", "test-key")
|
||||||
|
monkeypatch.delenv("OPENAI_MODEL", raising=False)
|
||||||
|
monkeypatch.delenv("OPENAI_REASONING_EFFORT", raising=False)
|
||||||
|
monkeypatch.delenv("OPENAI_TEXT_VERBOSITY", raising=False)
|
||||||
|
|
||||||
|
actual = load_runtime_config()
|
||||||
|
|
||||||
|
assert actual.model == "gpt-5.5"
|
||||||
|
assert actual.reasoning_effort == "low"
|
||||||
|
assert actual.text_verbosity == "low"
|
||||||
|
|
||||||
|
|
||||||
def test_load_runtime_config_reads_model_and_reasoning_from_env(monkeypatch: pytest.MonkeyPatch) -> None:
|
def test_load_runtime_config_reads_model_and_reasoning_from_env(monkeypatch: pytest.MonkeyPatch) -> None:
|
||||||
"""OpenAI model and reasoning effort can be overridden without code edits."""
|
"""OpenAI model and reasoning effort can be overridden without code edits."""
|
||||||
monkeypatch.setenv("OPENAI_API_KEY", "test-key")
|
monkeypatch.setenv("OPENAI_API_KEY", "test-key")
|
||||||
monkeypatch.setenv("OPENAI_MODEL", "gpt-test")
|
monkeypatch.setenv("OPENAI_MODEL", "gpt-test")
|
||||||
monkeypatch.setenv("OPENAI_REASONING_EFFORT", "low")
|
monkeypatch.setenv("OPENAI_REASONING_EFFORT", "low")
|
||||||
|
monkeypatch.setenv("OPENAI_TEXT_VERBOSITY", "medium")
|
||||||
|
|
||||||
actual = load_runtime_config()
|
actual = load_runtime_config()
|
||||||
|
|
||||||
assert actual.api_key == "test-key"
|
assert actual.api_key == "test-key"
|
||||||
assert actual.model == "gpt-test"
|
assert actual.model == "gpt-test"
|
||||||
assert actual.reasoning_effort == "low"
|
assert actual.reasoning_effort == "low"
|
||||||
|
assert actual.text_verbosity == "medium"
|
||||||
|
|
||||||
|
|
||||||
def test_load_runtime_config_rejects_invalid_reasoning_effort(monkeypatch: pytest.MonkeyPatch) -> None:
|
def test_load_runtime_config_rejects_invalid_reasoning_effort(monkeypatch: pytest.MonkeyPatch) -> None:
|
||||||
@@ -27,3 +43,13 @@ def test_load_runtime_config_rejects_invalid_reasoning_effort(monkeypatch: pytes
|
|||||||
|
|
||||||
with pytest.raises(RuntimeError, match="OPENAI_REASONING_EFFORT"):
|
with pytest.raises(RuntimeError, match="OPENAI_REASONING_EFFORT"):
|
||||||
load_runtime_config()
|
load_runtime_config()
|
||||||
|
|
||||||
|
|
||||||
|
def test_load_runtime_config_rejects_invalid_text_verbosity(monkeypatch: pytest.MonkeyPatch) -> None:
|
||||||
|
"""Invalid text verbosity should fail before an API call is attempted."""
|
||||||
|
monkeypatch.setenv("OPENAI_API_KEY", "test-key")
|
||||||
|
monkeypatch.delenv("OPENAI_REASONING_EFFORT", raising=False)
|
||||||
|
monkeypatch.setenv("OPENAI_TEXT_VERBOSITY", "tiny")
|
||||||
|
|
||||||
|
with pytest.raises(RuntimeError, match="OPENAI_TEXT_VERBOSITY"):
|
||||||
|
load_runtime_config()
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ class FakeResponse:
|
|||||||
|
|
||||||
def __init__(self, *, output_text: str, incomplete_details: object | None = None) -> None:
|
def __init__(self, *, output_text: str, incomplete_details: object | None = None) -> None:
|
||||||
self.output_text = output_text
|
self.output_text = output_text
|
||||||
self.model = "gpt-5.5-2026-04-23"
|
self.model = "gpt-5.5"
|
||||||
self.status = "completed"
|
self.status = "completed"
|
||||||
self.incomplete_details = incomplete_details
|
self.incomplete_details = incomplete_details
|
||||||
self.error = None
|
self.error = None
|
||||||
@@ -50,23 +50,25 @@ class FakeClient:
|
|||||||
self.responses = FakeResponsesResource(response)
|
self.responses = FakeResponsesResource(response)
|
||||||
|
|
||||||
|
|
||||||
def test_call_responses_api_sends_reasoning_and_omits_temperature() -> None:
|
def test_call_responses_api_sends_reasoning_text_controls_and_omits_temperature() -> None:
|
||||||
"""GPT-5.5 requests should use reasoning controls instead of temperature."""
|
"""GPT-5.5 requests should use reasoning/text controls instead of temperature."""
|
||||||
fake_client = FakeClient(FakeResponse(output_text=" 0\n"))
|
fake_client = FakeClient(FakeResponse(output_text=" 0\n"))
|
||||||
|
|
||||||
actual = call_responses_api(
|
actual = call_responses_api(
|
||||||
client=fake_client, # type: ignore[arg-type]
|
client=fake_client, # type: ignore[arg-type]
|
||||||
model="gpt-5.5-2026-04-23",
|
model="gpt-5.5",
|
||||||
reasoning_effort="none",
|
reasoning_effort="none",
|
||||||
system_content="Return one number.",
|
system_content="Return one number.",
|
||||||
user_text="Classify.",
|
user_text="Classify.",
|
||||||
image_data_urls=[],
|
image_data_urls=[],
|
||||||
max_output_tokens=128,
|
max_output_tokens=128,
|
||||||
|
text_verbosity="low",
|
||||||
)
|
)
|
||||||
|
|
||||||
assert actual.text == "0"
|
assert actual.text == "0"
|
||||||
assert fake_client.responses.create_params["reasoning"] == {"effort": "none"}
|
assert fake_client.responses.create_params["reasoning"] == {"effort": "none"}
|
||||||
assert fake_client.responses.create_params["max_output_tokens"] == 128
|
assert fake_client.responses.create_params["max_output_tokens"] == 128
|
||||||
|
assert fake_client.responses.create_params["text"] == {"verbosity": "low"}
|
||||||
assert "temperature" not in fake_client.responses.create_params
|
assert "temperature" not in fake_client.responses.create_params
|
||||||
|
|
||||||
|
|
||||||
@@ -87,17 +89,21 @@ def test_call_responses_api_sends_structured_text_format() -> None:
|
|||||||
|
|
||||||
actual = call_responses_api(
|
actual = call_responses_api(
|
||||||
client=fake_client, # type: ignore[arg-type]
|
client=fake_client, # type: ignore[arg-type]
|
||||||
model="gpt-5.5-2026-04-23",
|
model="gpt-5.5",
|
||||||
reasoning_effort="low",
|
reasoning_effort="low",
|
||||||
system_content="Return JSON.",
|
system_content="Return JSON.",
|
||||||
user_text="Classify.",
|
user_text="Classify.",
|
||||||
image_data_urls=[],
|
image_data_urls=[],
|
||||||
max_output_tokens=128,
|
max_output_tokens=128,
|
||||||
response_text_format=response_text_format,
|
response_text_format=response_text_format,
|
||||||
|
text_verbosity="low",
|
||||||
)
|
)
|
||||||
|
|
||||||
assert actual.text.startswith("{")
|
assert actual.text.startswith("{")
|
||||||
assert fake_client.responses.create_params["text"] == {"format": response_text_format}
|
assert fake_client.responses.create_params["text"] == {
|
||||||
|
"format": response_text_format,
|
||||||
|
"verbosity": "low",
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
def test_call_responses_api_returns_incomplete_diagnostics_for_empty_text() -> None:
|
def test_call_responses_api_returns_incomplete_diagnostics_for_empty_text() -> None:
|
||||||
@@ -111,7 +117,7 @@ def test_call_responses_api_returns_incomplete_diagnostics_for_empty_text() -> N
|
|||||||
|
|
||||||
actual = call_responses_api(
|
actual = call_responses_api(
|
||||||
client=fake_client, # type: ignore[arg-type]
|
client=fake_client, # type: ignore[arg-type]
|
||||||
model="gpt-5.5-2026-04-23",
|
model="gpt-5.5",
|
||||||
reasoning_effort="low",
|
reasoning_effort="low",
|
||||||
system_content="Return one number.",
|
system_content="Return one number.",
|
||||||
user_text="Classify.",
|
user_text="Classify.",
|
||||||
|
|||||||
@@ -22,7 +22,9 @@ YOUR_API_KEY = os.getenv("OPENAI_API_KEY")
|
|||||||
if YOUR_API_KEY is None:
|
if YOUR_API_KEY is None:
|
||||||
raise RuntimeError("OPENAI_API_KEY が環境変数に設定されていません。")
|
raise RuntimeError("OPENAI_API_KEY が環境変数に設定されていません。")
|
||||||
|
|
||||||
gpt_model = "gpt-5.4"
|
gpt_model = "gpt-5.5"
|
||||||
|
reasoning_effort = os.getenv("OPENAI_REASONING_EFFORT", "low")
|
||||||
|
text_verbosity = os.getenv("OPENAI_TEXT_VERBOSITY", "low")
|
||||||
|
|
||||||
# =========================
|
# =========================
|
||||||
# 入出力ファイル
|
# 入出力ファイル
|
||||||
@@ -355,7 +357,8 @@ def call_gpt(client, model, system_content: str, user_text: str, images_data_url
|
|||||||
{"role": "system", "content": system_content},
|
{"role": "system", "content": system_content},
|
||||||
{"role": "user", "content": content_parts},
|
{"role": "user", "content": content_parts},
|
||||||
],
|
],
|
||||||
temperature=0.0,
|
reasoning={"effort": reasoning_effort},
|
||||||
|
text={"verbosity": text_verbosity},
|
||||||
max_output_tokens=max_output_tokens,
|
max_output_tokens=max_output_tokens,
|
||||||
)
|
)
|
||||||
return resp.output_text or ""
|
return resp.output_text or ""
|
||||||
@@ -440,6 +443,8 @@ def write_debug_entry(
|
|||||||
f.write("=" * 60 + "\n")
|
f.write("=" * 60 + "\n")
|
||||||
f.write(f"DEBUG TIME : {_now_str()}\n")
|
f.write(f"DEBUG TIME : {_now_str()}\n")
|
||||||
f.write(f"MODEL : {gpt_model}\n")
|
f.write(f"MODEL : {gpt_model}\n")
|
||||||
|
f.write(f"REASONING : {reasoning_effort}\n")
|
||||||
|
f.write(f"VERBOSITY : {text_verbosity}\n")
|
||||||
f.write(f"TIMEFRAME : {timeframe}\n")
|
f.write(f"TIMEFRAME : {timeframe}\n")
|
||||||
f.write(f"TREND_STATE(H4) : {trend_state} (0=RANGE,1=UP,2=DOWN)\n")
|
f.write(f"TREND_STATE(H4) : {trend_state} (0=RANGE,1=UP,2=DOWN)\n")
|
||||||
f.write(f"SELECTED_STRATEGY : {','.join(str(x) for x in selected_strategies)}\n")
|
f.write(f"SELECTED_STRATEGY : {','.join(str(x) for x in selected_strategies)}\n")
|
||||||
@@ -627,4 +632,4 @@ def _write_outputs(numeric_list):
|
|||||||
# 実行
|
# 実行
|
||||||
# =========================
|
# =========================
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
run_pipeline()
|
run_pipeline()
|
||||||
|
|||||||
@@ -22,7 +22,9 @@ YOUR_API_KEY = os.getenv("OPENAI_API_KEY")
|
|||||||
if YOUR_API_KEY is None:
|
if YOUR_API_KEY is None:
|
||||||
raise RuntimeError("OPENAI_API_KEY が環境変数に設定されていません。")
|
raise RuntimeError("OPENAI_API_KEY が環境変数に設定されていません。")
|
||||||
|
|
||||||
gpt_model = "gpt-5.4"
|
gpt_model = "gpt-5.5"
|
||||||
|
reasoning_effort = os.getenv("OPENAI_REASONING_EFFORT", "low")
|
||||||
|
text_verbosity = os.getenv("OPENAI_TEXT_VERBOSITY", "low")
|
||||||
|
|
||||||
# =========================
|
# =========================
|
||||||
# 入出力ファイル
|
# 入出力ファイル
|
||||||
@@ -62,6 +64,8 @@ def write_debug_trend(path: str, current_price: float, numeric_summary: str, gpt
|
|||||||
f.write("=" * 60 + "\n")
|
f.write("=" * 60 + "\n")
|
||||||
f.write(f"DEBUG TIME : {_now_str()}\n")
|
f.write(f"DEBUG TIME : {_now_str()}\n")
|
||||||
f.write(f"MODEL : {gpt_model}\n")
|
f.write(f"MODEL : {gpt_model}\n")
|
||||||
|
f.write(f"REASONING : {reasoning_effort}\n")
|
||||||
|
f.write(f"VERBOSITY : {text_verbosity}\n")
|
||||||
f.write(f"CURRENT PRICE : {current_price:.2f}\n")
|
f.write(f"CURRENT PRICE : {current_price:.2f}\n")
|
||||||
f.write("=" * 60 + "\n\n")
|
f.write("=" * 60 + "\n\n")
|
||||||
f.write("---- NUMERIC SUMMARY START ----\n")
|
f.write("---- NUMERIC SUMMARY START ----\n")
|
||||||
@@ -289,7 +293,8 @@ def call_gpt_trend(client, model, system_content: str, user_text: str, image_dat
|
|||||||
{"role": "system", "content": system_content},
|
{"role": "system", "content": system_content},
|
||||||
{"role": "user", "content": content_parts},
|
{"role": "user", "content": content_parts},
|
||||||
],
|
],
|
||||||
temperature=0.0,
|
reasoning={"effort": reasoning_effort},
|
||||||
|
text={"verbosity": text_verbosity},
|
||||||
max_output_tokens=max_output_tokens,
|
max_output_tokens=max_output_tokens,
|
||||||
)
|
)
|
||||||
return (resp.output_text or "").strip()
|
return (resp.output_text or "").strip()
|
||||||
@@ -485,4 +490,4 @@ def run_pipeline():
|
|||||||
# 実行
|
# 実行
|
||||||
# =========================
|
# =========================
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
run_pipeline()
|
run_pipeline()
|
||||||
|
|||||||
Reference in New Issue
Block a user