feat(V2): IBKR settings + env-specific credentials
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -92,6 +92,83 @@ class AlpacaSettings(_Sub):
|
||||
max_leverage: int = 1
|
||||
|
||||
|
||||
class IBKRSettings(_Sub):
|
||||
model_config = SettingsConfigDict(
|
||||
env_file=".env",
|
||||
env_file_encoding="utf-8",
|
||||
env_prefix="IBKR_",
|
||||
extra="ignore",
|
||||
)
|
||||
consumer_key: str | None = None
|
||||
access_token: str | None = None
|
||||
access_token_secret: SecretStr | None = None
|
||||
signature_key_path: str | None = None
|
||||
encryption_key_path: str | None = None
|
||||
dh_prime: SecretStr | None = None
|
||||
|
||||
consumer_key_testnet: str | None = None
|
||||
access_token_testnet: str | None = None
|
||||
access_token_secret_testnet: SecretStr | None = None
|
||||
signature_key_path_testnet: str | None = None
|
||||
encryption_key_path_testnet: str | None = None
|
||||
account_id_testnet: str | None = None
|
||||
|
||||
consumer_key_live: str | None = None
|
||||
access_token_live: str | None = None
|
||||
access_token_secret_live: SecretStr | None = None
|
||||
signature_key_path_live: str | None = None
|
||||
encryption_key_path_live: str | None = None
|
||||
account_id_live: str | None = None
|
||||
|
||||
url_live: str = "https://api.ibkr.com/v1/api"
|
||||
url_testnet: str = "https://api.ibkr.com/v1/api"
|
||||
ws_url_live: str = "wss://api.ibkr.com/v1/api/ws"
|
||||
ws_url_testnet: str = "wss://api.ibkr.com/v1/api/ws"
|
||||
max_leverage: int = 4
|
||||
ws_max_subscriptions: int = 80
|
||||
ws_idle_timeout_s: int = 300
|
||||
|
||||
def credentials(self, env: str) -> dict:
|
||||
if env == "testnet":
|
||||
ck = self.consumer_key_testnet or self.consumer_key
|
||||
at = self.access_token_testnet or self.access_token
|
||||
ats = self.access_token_secret_testnet or self.access_token_secret
|
||||
sigp = self.signature_key_path_testnet or self.signature_key_path
|
||||
encp = self.encryption_key_path_testnet or self.encryption_key_path
|
||||
acct = self.account_id_testnet
|
||||
elif env == "mainnet":
|
||||
ck = self.consumer_key_live or self.consumer_key
|
||||
at = self.access_token_live or self.access_token
|
||||
ats = self.access_token_secret_live or self.access_token_secret
|
||||
sigp = self.signature_key_path_live or self.signature_key_path
|
||||
encp = self.encryption_key_path_live or self.encryption_key_path
|
||||
acct = self.account_id_live
|
||||
else:
|
||||
raise ValueError(f"unknown ibkr env: {env}")
|
||||
|
||||
missing = [
|
||||
n for n, v in [
|
||||
("consumer_key", ck), ("access_token", at),
|
||||
("access_token_secret", ats), ("signature_key_path", sigp),
|
||||
("encryption_key_path", encp), ("account_id", acct),
|
||||
("dh_prime", self.dh_prime),
|
||||
] if not v
|
||||
]
|
||||
if missing:
|
||||
raise ValueError(
|
||||
f"IBKR credentials not configured for env={env}: missing {missing}"
|
||||
)
|
||||
return {
|
||||
"consumer_key": ck,
|
||||
"access_token": at,
|
||||
"access_token_secret": ats.get_secret_value(), # type: ignore[union-attr]
|
||||
"signature_key_path": sigp,
|
||||
"encryption_key_path": encp,
|
||||
"account_id": acct,
|
||||
"dh_prime": self.dh_prime.get_secret_value(), # type: ignore[union-attr]
|
||||
}
|
||||
|
||||
|
||||
class MacroSettings(_Sub):
|
||||
model_config = SettingsConfigDict(
|
||||
env_file=".env",
|
||||
@@ -124,5 +201,6 @@ class Settings(_Sub):
|
||||
bybit: BybitSettings = Field(default_factory=lambda: BybitSettings()) # type: ignore[call-arg]
|
||||
hyperliquid: HyperliquidSettings = Field(default_factory=lambda: HyperliquidSettings()) # type: ignore[call-arg]
|
||||
alpaca: AlpacaSettings = Field(default_factory=lambda: AlpacaSettings()) # type: ignore[call-arg]
|
||||
ibkr: IBKRSettings = Field(default_factory=lambda: IBKRSettings()) # type: ignore[call-arg]
|
||||
macro: MacroSettings = Field(default_factory=lambda: MacroSettings()) # type: ignore[call-arg]
|
||||
sentiment: SentimentSettings = Field(default_factory=lambda: SentimentSettings()) # type: ignore[call-arg]
|
||||
|
||||
Reference in New Issue
Block a user