diff --git a/freqtrade/data/btanalysis.py b/freqtrade/data/btanalysis.py index edac74d51..96ab4927e 100644 --- a/freqtrade/data/btanalysis.py +++ b/freqtrade/data/btanalysis.py @@ -12,7 +12,7 @@ import pandas as pd from freqtrade.constants import LAST_BT_RESULT_FN, IntOrInf from freqtrade.exceptions import OperationalException -from freqtrade.misc import json_load +from freqtrade.misc import file_dump_json, json_load from freqtrade.optimize.backtest_caching import get_backtest_metadata_filename from freqtrade.persistence import LocalTrade, Trade, init_db from freqtrade.types import BacktestHistoryEntryType, BacktestResultType @@ -219,6 +219,21 @@ def delete_backtest_result(file_abs: Path): file_abs_meta.unlink() +def update_backtest_metadata(filename: Path, strategy: str, content: Dict[str, Any]): + """ + Updates backtest metadata file with new content. + :raises: ValueError if metadata file does not exist, or strategy is not in this file. + """ + metadata = load_backtest_metadata(filename) + if not metadata: + raise ValueError("File does not exist.") + if strategy not in metadata: + raise ValueError("Strategy not in metadata.") + metadata[strategy].update(content) + # Write data again. + file_dump_json(get_backtest_metadata_filename(filename), metadata) + + def find_existing_backtest_stats(dirname: Union[Path, str], run_ids: Dict[str, str], min_backtest_date: Optional[datetime] = None) -> Dict[str, Any]: """ diff --git a/freqtrade/rpc/api_server/api_backtest.py b/freqtrade/rpc/api_server/api_backtest.py index 6d3174a5a..3bfad2f56 100644 --- a/freqtrade/rpc/api_server/api_backtest.py +++ b/freqtrade/rpc/api_server/api_backtest.py @@ -10,14 +10,15 @@ from fastapi.exceptions import HTTPException from freqtrade.configuration.config_validation import validate_config_consistency from freqtrade.constants import Config -from freqtrade.data.btanalysis import (delete_backtest_result, get_backtest_resultlist, - load_and_merge_backtest_result) +from freqtrade.data.btanalysis import (delete_backtest_result, get_backtest_result, + get_backtest_resultlist, load_and_merge_backtest_result, + update_backtest_metadata) from freqtrade.enums import BacktestState from freqtrade.exceptions import DependencyException, OperationalException from freqtrade.exchange.common import remove_exchange_credentials from freqtrade.misc import deep_merge_dicts, is_file_in_dir -from freqtrade.rpc.api_server.api_schemas import (BacktestHistoryEntry, BacktestRequest, - BacktestResponse) +from freqtrade.rpc.api_server.api_schemas import (BacktestHistoryEntry, BacktestMetadataUpdate, + BacktestRequest, BacktestResponse) from freqtrade.rpc.api_server.deps import get_config from freqtrade.rpc.api_server.webserver_bgwork import ApiBG from freqtrade.rpc.rpc import RPCException @@ -281,3 +282,24 @@ def api_delete_backtest_history_entry(file: str, config=Depends(get_config)): delete_backtest_result(file_abs) return get_backtest_resultlist(config['user_data_dir'] / 'backtest_results') + + +@router.patch('/backtest/history/{file}', response_model=List[BacktestHistoryEntry], + tags=['webserver', 'backtest']) +def api_update_backtest_history_entry(file: str, body: BacktestMetadataUpdate, + config=Depends(get_config)): + # Get backtest result history, read from metadata files + bt_results_base: Path = config['user_data_dir'] / 'backtest_results' + file_abs = (bt_results_base / file).with_suffix('.json') + # Ensure file is in backtest_results directory + if not is_file_in_dir(file_abs, bt_results_base): + raise HTTPException(status_code=404, detail="File not found.") + content = { + 'notes': body.notes + } + try: + update_backtest_metadata(file_abs, body.strategy, content) + except ValueError as e: + raise HTTPException(status_code=400, detail=str(e)) + + return get_backtest_result(file_abs) diff --git a/freqtrade/rpc/api_server/api_schemas.py b/freqtrade/rpc/api_server/api_schemas.py index f96e586bb..ca39b11fd 100644 --- a/freqtrade/rpc/api_server/api_schemas.py +++ b/freqtrade/rpc/api_server/api_schemas.py @@ -529,6 +529,11 @@ class BacktestHistoryEntry(BaseModel): notes: Optional[str] = '' +class BacktestMetadataUpdate(BaseModel): + strategy: str + notes: Optional[str] + + class SysInfo(BaseModel): cpu_pct: List[float] ram_pct: float