diff --git a/freqtrade/rpc/api_server/api_v1.py b/freqtrade/rpc/api_server/api_v1.py index 39c8e9821..c2446d770 100644 --- a/freqtrade/rpc/api_server/api_v1.py +++ b/freqtrade/rpc/api_server/api_v1.py @@ -8,7 +8,6 @@ from fastapi.exceptions import HTTPException from freqtrade import __version__ from freqtrade.data.history import get_datahandler from freqtrade.enums import CandleType, RunMode, State, TradingMode -from freqtrade.exceptions import OperationalException from freqtrade.rpc import RPC from freqtrade.rpc.api_server.api_pairlists import handleExchangePayload from freqtrade.rpc.api_server.api_schemas import ( @@ -21,14 +20,12 @@ from freqtrade.rpc.api_server.api_schemas import ( DeleteLockRequest, DeleteTrade, Entry, - ExchangeListResponse, Exit, ForceEnterPayload, ForceEnterResponse, ForceExitPayload, FreqAIModelListResponse, Health, - HyperoptLossListResponse, ListCustomData, Locks, LocksPayload, @@ -48,8 +45,6 @@ from freqtrade.rpc.api_server.api_schemas import ( ShowConfig, Stats, StatusMsg, - StrategyListResponse, - StrategyResponse, SysInfo, Version, WhitelistResponse, @@ -434,75 +429,6 @@ def plot_config( raise HTTPException(status_code=502, detail=str(e)) -@router.get("/strategies", response_model=StrategyListResponse, tags=["strategy"]) -def list_strategies(config=Depends(get_config)): - from freqtrade.resolvers.strategy_resolver import StrategyResolver - - strategies = StrategyResolver.search_all_objects( - config, False, config.get("recursive_strategy_search", False) - ) - strategies = sorted(strategies, key=lambda x: x["name"]) - - return {"strategies": [x["name"] for x in strategies]} - - -@router.get("/strategy/{strategy}", response_model=StrategyResponse, tags=["strategy"]) -def get_strategy(strategy: str, config=Depends(get_config)): - if ":" in strategy: - raise HTTPException(status_code=500, detail="base64 encoded strategies are not allowed.") - - config_ = deepcopy(config) - from freqtrade.resolvers.strategy_resolver import StrategyResolver - - try: - strategy_obj = StrategyResolver._load_strategy( - strategy, config_, extra_dir=config_.get("strategy_path") - ) - except OperationalException: - raise HTTPException(status_code=404, detail="Strategy not found") - except Exception as e: - raise HTTPException(status_code=502, detail=str(e)) - return { - "strategy": strategy_obj.get_strategy_name(), - "code": strategy_obj.__source__, - "timeframe": getattr(strategy_obj, "timeframe", None), - } - - -@router.get("/exchanges", response_model=ExchangeListResponse, tags=[]) -def list_exchanges(config=Depends(get_config)): - from freqtrade.exchange import list_available_exchanges - - exchanges = list_available_exchanges(config) - return { - "exchanges": exchanges, - } - - -@router.get( - "/hyperoptloss", response_model=HyperoptLossListResponse, tags=["hyperopt", "webserver"] -) -def list_hyperoptloss( - config=Depends(get_config), -): - import textwrap - - from freqtrade.resolvers.hyperopt_resolver import HyperOptLossResolver - - loss_functions = HyperOptLossResolver.search_all_objects(config, False) - loss_functions = sorted(loss_functions, key=lambda x: x["name"]) - - return { - "loss_functions": [ - { - "name": x["name"], - "description": textwrap.dedent((x["class"].__doc__ or "").strip()), - } - for x in loss_functions - ] - } - - @router.get("/freqaimodels", response_model=FreqAIModelListResponse, tags=["freqai"]) def list_freqaimodels(config=Depends(get_config)): from freqtrade.resolvers.freqaimodel_resolver import FreqaiModelResolver diff --git a/freqtrade/rpc/api_server/api_webserver.py b/freqtrade/rpc/api_server/api_webserver.py new file mode 100644 index 000000000..894bd751b --- /dev/null +++ b/freqtrade/rpc/api_server/api_webserver.py @@ -0,0 +1,89 @@ +import logging +from copy import deepcopy + +from fastapi import APIRouter, Depends +from fastapi.exceptions import HTTPException + +from freqtrade.exceptions import OperationalException +from freqtrade.rpc.api_server.api_schemas import ( + ExchangeListResponse, + HyperoptLossListResponse, + StrategyListResponse, + StrategyResponse, +) +from freqtrade.rpc.api_server.deps import get_config + + +logger = logging.getLogger(__name__) + +# Private API, protected by authentication and webserver_mode dependency +router = APIRouter() + + +@router.get("/strategies", response_model=StrategyListResponse, tags=["strategy"]) +def list_strategies(config=Depends(get_config)): + from freqtrade.resolvers.strategy_resolver import StrategyResolver + + strategies = StrategyResolver.search_all_objects( + config, False, config.get("recursive_strategy_search", False) + ) + strategies = sorted(strategies, key=lambda x: x["name"]) + + return {"strategies": [x["name"] for x in strategies]} + + +@router.get("/strategy/{strategy}", response_model=StrategyResponse, tags=["strategy"]) +def get_strategy(strategy: str, config=Depends(get_config)): + if ":" in strategy: + raise HTTPException(status_code=500, detail="base64 encoded strategies are not allowed.") + + config_ = deepcopy(config) + from freqtrade.resolvers.strategy_resolver import StrategyResolver + + try: + strategy_obj = StrategyResolver._load_strategy( + strategy, config_, extra_dir=config_.get("strategy_path") + ) + except OperationalException: + raise HTTPException(status_code=404, detail="Strategy not found") + except Exception as e: + raise HTTPException(status_code=502, detail=str(e)) + return { + "strategy": strategy_obj.get_strategy_name(), + "code": strategy_obj.__source__, + "timeframe": getattr(strategy_obj, "timeframe", None), + } + + +@router.get("/exchanges", response_model=ExchangeListResponse, tags=[]) +def list_exchanges(config=Depends(get_config)): + from freqtrade.exchange import list_available_exchanges + + exchanges = list_available_exchanges(config) + return { + "exchanges": exchanges, + } + + +@router.get( + "/hyperoptloss", response_model=HyperoptLossListResponse, tags=["hyperopt", "webserver"] +) +def list_hyperoptloss( + config=Depends(get_config), +): + import textwrap + + from freqtrade.resolvers.hyperopt_resolver import HyperOptLossResolver + + loss_functions = HyperOptLossResolver.search_all_objects(config, False) + loss_functions = sorted(loss_functions, key=lambda x: x["name"]) + + return { + "loss_functions": [ + { + "name": x["name"], + "description": textwrap.dedent((x["class"].__doc__ or "").strip()), + } + for x in loss_functions + ] + } diff --git a/freqtrade/rpc/api_server/webserver.py b/freqtrade/rpc/api_server/webserver.py index aa81684fc..b5eaba796 100644 --- a/freqtrade/rpc/api_server/webserver.py +++ b/freqtrade/rpc/api_server/webserver.py @@ -124,6 +124,7 @@ class ApiServer(RPCHandler): from freqtrade.rpc.api_server.api_pairlists import router as api_pairlists from freqtrade.rpc.api_server.api_v1 import router as api_v1 from freqtrade.rpc.api_server.api_v1 import router_public as api_v1_public + from freqtrade.rpc.api_server.api_webserver import router as api_webserver from freqtrade.rpc.api_server.api_ws import router as ws_router from freqtrade.rpc.api_server.deps import is_webserver_mode from freqtrade.rpc.api_server.web_ui import router_ui @@ -136,6 +137,11 @@ class ApiServer(RPCHandler): prefix="/api/v1", dependencies=[Depends(http_basic_or_jwt_token)], ) + app.include_router( + api_webserver, + prefix="/api/v1", + dependencies=[Depends(http_basic_or_jwt_token), Depends(is_webserver_mode)], + ) app.include_router( api_backtest, prefix="/api/v1",