Source code for tradeexecutor.strategy.freqtrade.freqtrade_client
"""REST API client for Freqtrade instances."""
import logging
import requests
logger = logging.getLogger(__name__)
[docs]class FreqtradeClient:
[docs] def __init__(
self,
api_url: str,
api_username: str,
api_password: str,
timeout: float = 5.0,
):
self.api_url = api_url.rstrip("/")
self.api_username = api_username
self.api_password = api_password
self.timeout = timeout
self._token = None
self.session = requests.Session()
def _get_jwt_token(self) -> str:
if self._token:
return self._token
url = f"{self.api_url}/api/v1/login"
payload = {
"username": self.api_username,
"password": self.api_password,
}
response = self.session.post(url, json=payload, timeout=self.timeout)
response.raise_for_status()
data = response.json()
self._token = data.get("access_token")
if not self._token:
raise ValueError("No access token in Freqtrade login response")
return self._token
def _make_request(
self,
method: str,
endpoint: str,
**kwargs
) -> dict:
url = f"{self.api_url}{endpoint}"
kwargs.setdefault("timeout", self.timeout)
# Ensure we have a valid token
token = self._get_jwt_token()
# Add JWT authorization header
if "headers" not in kwargs:
kwargs["headers"] = {}
kwargs["headers"]["Authorization"] = f"Bearer {token}"
response = self.session.request(method, url, **kwargs)
response.raise_for_status()
return response.json()
[docs] def get_balance(self) -> dict:
"""Query /api/v1/balance endpoint.
Returns:
Dict with keys: total, free, used (amounts in reserve currency)
Raises:
requests.RequestException: If API call fails
"""
return self._make_request("GET", "/api/v1/balance")
[docs] def get_status(self) -> dict:
"""Query /api/v1/status for bot and trade status.
Returns:
Dict with current bot status and open trades
Raises:
requests.RequestException: If API call fails
"""
return self._make_request("GET", "/api/v1/status")
[docs] def get_performance(self) -> dict:
"""Query /api/v1/performance for trade performance.
Returns:
Dict with per-pair trade performance metrics
Raises:
requests.RequestException: If API call fails
"""
return self._make_request("GET", "/api/v1/performance")