ruff format: rpc modules
This commit is contained in:
@@ -49,67 +49,67 @@ def __run_backtest_bg(btconfig: Config):
|
||||
asyncio.set_event_loop(asyncio.new_event_loop())
|
||||
try:
|
||||
# Reload strategy
|
||||
lastconfig = ApiBG.bt['last_config']
|
||||
lastconfig = ApiBG.bt["last_config"]
|
||||
strat = StrategyResolver.load_strategy(btconfig)
|
||||
validate_config_consistency(btconfig)
|
||||
|
||||
if (
|
||||
not ApiBG.bt['bt']
|
||||
or lastconfig.get('timeframe') != strat.timeframe
|
||||
or lastconfig.get('timeframe_detail') != btconfig.get('timeframe_detail')
|
||||
or lastconfig.get('timerange') != btconfig['timerange']
|
||||
not ApiBG.bt["bt"]
|
||||
or lastconfig.get("timeframe") != strat.timeframe
|
||||
or lastconfig.get("timeframe_detail") != btconfig.get("timeframe_detail")
|
||||
or lastconfig.get("timerange") != btconfig["timerange"]
|
||||
):
|
||||
from freqtrade.optimize.backtesting import Backtesting
|
||||
ApiBG.bt['bt'] = Backtesting(btconfig)
|
||||
ApiBG.bt['bt'].load_bt_data_detail()
|
||||
|
||||
ApiBG.bt["bt"] = Backtesting(btconfig)
|
||||
ApiBG.bt["bt"].load_bt_data_detail()
|
||||
else:
|
||||
ApiBG.bt['bt'].config = btconfig
|
||||
ApiBG.bt['bt'].init_backtest()
|
||||
ApiBG.bt["bt"].config = btconfig
|
||||
ApiBG.bt["bt"].init_backtest()
|
||||
# Only reload data if timeframe changed.
|
||||
if (
|
||||
not ApiBG.bt['data']
|
||||
or not ApiBG.bt['timerange']
|
||||
or lastconfig.get('timeframe') != strat.timeframe
|
||||
or lastconfig.get('timerange') != btconfig['timerange']
|
||||
not ApiBG.bt["data"]
|
||||
or not ApiBG.bt["timerange"]
|
||||
or lastconfig.get("timeframe") != strat.timeframe
|
||||
or lastconfig.get("timerange") != btconfig["timerange"]
|
||||
):
|
||||
ApiBG.bt['data'], ApiBG.bt['timerange'] = ApiBG.bt[
|
||||
'bt'].load_bt_data()
|
||||
ApiBG.bt["data"], ApiBG.bt["timerange"] = ApiBG.bt["bt"].load_bt_data()
|
||||
|
||||
lastconfig['timerange'] = btconfig['timerange']
|
||||
lastconfig['timeframe'] = strat.timeframe
|
||||
lastconfig['protections'] = btconfig.get('protections', [])
|
||||
lastconfig['enable_protections'] = btconfig.get('enable_protections')
|
||||
lastconfig['dry_run_wallet'] = btconfig.get('dry_run_wallet')
|
||||
lastconfig["timerange"] = btconfig["timerange"]
|
||||
lastconfig["timeframe"] = strat.timeframe
|
||||
lastconfig["protections"] = btconfig.get("protections", [])
|
||||
lastconfig["enable_protections"] = btconfig.get("enable_protections")
|
||||
lastconfig["dry_run_wallet"] = btconfig.get("dry_run_wallet")
|
||||
|
||||
ApiBG.bt['bt'].enable_protections = btconfig.get('enable_protections', False)
|
||||
ApiBG.bt['bt'].strategylist = [strat]
|
||||
ApiBG.bt['bt'].results = get_BacktestResultType_default()
|
||||
ApiBG.bt['bt'].load_prior_backtest()
|
||||
ApiBG.bt["bt"].enable_protections = btconfig.get("enable_protections", False)
|
||||
ApiBG.bt["bt"].strategylist = [strat]
|
||||
ApiBG.bt["bt"].results = get_BacktestResultType_default()
|
||||
ApiBG.bt["bt"].load_prior_backtest()
|
||||
|
||||
ApiBG.bt['bt'].abort = False
|
||||
ApiBG.bt["bt"].abort = False
|
||||
strategy_name = strat.get_strategy_name()
|
||||
if (ApiBG.bt['bt'].results and
|
||||
strategy_name in ApiBG.bt['bt'].results['strategy']):
|
||||
if ApiBG.bt["bt"].results and strategy_name in ApiBG.bt["bt"].results["strategy"]:
|
||||
# When previous result hash matches - reuse that result and skip backtesting.
|
||||
logger.info(f'Reusing result of previous backtest for {strategy_name}')
|
||||
logger.info(f"Reusing result of previous backtest for {strategy_name}")
|
||||
else:
|
||||
min_date, max_date = ApiBG.bt['bt'].backtest_one_strategy(
|
||||
strat, ApiBG.bt['data'], ApiBG.bt['timerange'])
|
||||
min_date, max_date = ApiBG.bt["bt"].backtest_one_strategy(
|
||||
strat, ApiBG.bt["data"], ApiBG.bt["timerange"]
|
||||
)
|
||||
|
||||
ApiBG.bt['bt'].results = generate_backtest_stats(
|
||||
ApiBG.bt['data'], ApiBG.bt['bt'].all_results,
|
||||
min_date=min_date, max_date=max_date)
|
||||
ApiBG.bt["bt"].results = generate_backtest_stats(
|
||||
ApiBG.bt["data"], ApiBG.bt["bt"].all_results, min_date=min_date, max_date=max_date
|
||||
)
|
||||
|
||||
if btconfig.get('export', 'none') == 'trades':
|
||||
combined_res = combined_dataframes_with_rel_mean(ApiBG.bt['data'], min_date, max_date)
|
||||
if btconfig.get("export", "none") == "trades":
|
||||
combined_res = combined_dataframes_with_rel_mean(ApiBG.bt["data"], min_date, max_date)
|
||||
fn = store_backtest_stats(
|
||||
btconfig['exportfilename'],
|
||||
ApiBG.bt['bt'].results,
|
||||
btconfig["exportfilename"],
|
||||
ApiBG.bt["bt"].results,
|
||||
datetime.now().strftime("%Y-%m-%d_%H-%M-%S"),
|
||||
market_change_data=combined_res
|
||||
)
|
||||
ApiBG.bt['bt'].results['metadata'][strategy_name]['filename'] = str(fn.stem)
|
||||
ApiBG.bt['bt'].results['metadata'][strategy_name]['strategy'] = strategy_name
|
||||
market_change_data=combined_res,
|
||||
)
|
||||
ApiBG.bt["bt"].results["metadata"][strategy_name]["filename"] = str(fn.stem)
|
||||
ApiBG.bt["bt"].results["metadata"][strategy_name]["strategy"] = strategy_name
|
||||
|
||||
logger.info("Backtest finished.")
|
||||
|
||||
@@ -118,38 +118,38 @@ def __run_backtest_bg(btconfig: Config):
|
||||
|
||||
except (Exception, OperationalException, DependencyException) as e:
|
||||
logger.exception(f"Backtesting caused an error: {e}")
|
||||
ApiBG.bt['bt_error'] = str(e)
|
||||
ApiBG.bt["bt_error"] = str(e)
|
||||
finally:
|
||||
ApiBG.bgtask_running = False
|
||||
|
||||
|
||||
@router.post('/backtest', response_model=BacktestResponse, tags=['webserver', 'backtest'])
|
||||
@router.post("/backtest", response_model=BacktestResponse, tags=["webserver", "backtest"])
|
||||
async def api_start_backtest(
|
||||
bt_settings: BacktestRequest, background_tasks: BackgroundTasks,
|
||||
config=Depends(get_config)):
|
||||
ApiBG.bt['bt_error'] = None
|
||||
bt_settings: BacktestRequest, background_tasks: BackgroundTasks, config=Depends(get_config)
|
||||
):
|
||||
ApiBG.bt["bt_error"] = None
|
||||
"""Start backtesting if not done so already"""
|
||||
if ApiBG.bgtask_running:
|
||||
raise RPCException('Bot Background task already running')
|
||||
raise RPCException("Bot Background task already running")
|
||||
|
||||
if ':' in bt_settings.strategy:
|
||||
if ":" in bt_settings.strategy:
|
||||
raise HTTPException(status_code=500, detail="base64 encoded strategies are not allowed.")
|
||||
|
||||
btconfig = deepcopy(config)
|
||||
remove_exchange_credentials(btconfig['exchange'], True)
|
||||
remove_exchange_credentials(btconfig["exchange"], True)
|
||||
settings = dict(bt_settings)
|
||||
if settings.get('freqai', None) is not None:
|
||||
settings['freqai'] = dict(settings['freqai'])
|
||||
if settings.get("freqai", None) is not None:
|
||||
settings["freqai"] = dict(settings["freqai"])
|
||||
# Pydantic models will contain all keys, but non-provided ones are None
|
||||
|
||||
btconfig = deep_merge_dicts(settings, btconfig, allow_null_overrides=False)
|
||||
try:
|
||||
btconfig['stake_amount'] = float(btconfig['stake_amount'])
|
||||
btconfig["stake_amount"] = float(btconfig["stake_amount"])
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
# Force dry-run for backtesting
|
||||
btconfig['dry_run'] = True
|
||||
btconfig["dry_run"] = True
|
||||
|
||||
# Start backtesting
|
||||
# Initialize backtesting object
|
||||
@@ -166,39 +166,41 @@ async def api_start_backtest(
|
||||
}
|
||||
|
||||
|
||||
@router.get('/backtest', response_model=BacktestResponse, tags=['webserver', 'backtest'])
|
||||
@router.get("/backtest", response_model=BacktestResponse, tags=["webserver", "backtest"])
|
||||
def api_get_backtest():
|
||||
"""
|
||||
Get backtesting result.
|
||||
Returns Result after backtesting has been ran.
|
||||
"""
|
||||
from freqtrade.persistence import LocalTrade
|
||||
|
||||
if ApiBG.bgtask_running:
|
||||
return {
|
||||
"status": "running",
|
||||
"running": True,
|
||||
"step": (ApiBG.bt['bt'].progress.action if ApiBG.bt['bt']
|
||||
else str(BacktestState.STARTUP)),
|
||||
"progress": ApiBG.bt['bt'].progress.progress if ApiBG.bt['bt'] else 0,
|
||||
"step": (
|
||||
ApiBG.bt["bt"].progress.action if ApiBG.bt["bt"] else str(BacktestState.STARTUP)
|
||||
),
|
||||
"progress": ApiBG.bt["bt"].progress.progress if ApiBG.bt["bt"] else 0,
|
||||
"trade_count": len(LocalTrade.trades),
|
||||
"status_msg": "Backtest running",
|
||||
}
|
||||
|
||||
if not ApiBG.bt['bt']:
|
||||
if not ApiBG.bt["bt"]:
|
||||
return {
|
||||
"status": "not_started",
|
||||
"running": False,
|
||||
"step": "",
|
||||
"progress": 0,
|
||||
"status_msg": "Backtest not yet executed"
|
||||
"status_msg": "Backtest not yet executed",
|
||||
}
|
||||
if ApiBG.bt['bt_error']:
|
||||
if ApiBG.bt["bt_error"]:
|
||||
return {
|
||||
"status": "error",
|
||||
"running": False,
|
||||
"step": "",
|
||||
"progress": 0,
|
||||
"status_msg": f"Backtest failed with {ApiBG.bt['bt_error']}"
|
||||
"status_msg": f"Backtest failed with {ApiBG.bt['bt_error']}",
|
||||
}
|
||||
|
||||
return {
|
||||
@@ -207,11 +209,11 @@ def api_get_backtest():
|
||||
"status_msg": "Backtest ended",
|
||||
"step": "finished",
|
||||
"progress": 1,
|
||||
"backtest_result": ApiBG.bt['bt'].results,
|
||||
"backtest_result": ApiBG.bt["bt"].results,
|
||||
}
|
||||
|
||||
|
||||
@router.delete('/backtest', response_model=BacktestResponse, tags=['webserver', 'backtest'])
|
||||
@router.delete("/backtest", response_model=BacktestResponse, tags=["webserver", "backtest"])
|
||||
def api_delete_backtest():
|
||||
"""Reset backtesting"""
|
||||
if ApiBG.bgtask_running:
|
||||
@@ -222,12 +224,12 @@ def api_delete_backtest():
|
||||
"progress": 0,
|
||||
"status_msg": "Backtest running",
|
||||
}
|
||||
if ApiBG.bt['bt']:
|
||||
ApiBG.bt['bt'].cleanup()
|
||||
del ApiBG.bt['bt']
|
||||
ApiBG.bt['bt'] = None
|
||||
del ApiBG.bt['data']
|
||||
ApiBG.bt['data'] = None
|
||||
if ApiBG.bt["bt"]:
|
||||
ApiBG.bt["bt"].cleanup()
|
||||
del ApiBG.bt["bt"]
|
||||
ApiBG.bt["bt"] = None
|
||||
del ApiBG.bt["data"]
|
||||
ApiBG.bt["data"] = None
|
||||
logger.info("Backtesting reset")
|
||||
return {
|
||||
"status": "reset",
|
||||
@@ -238,7 +240,7 @@ def api_delete_backtest():
|
||||
}
|
||||
|
||||
|
||||
@router.get('/backtest/abort', response_model=BacktestResponse, tags=['webserver', 'backtest'])
|
||||
@router.get("/backtest/abort", response_model=BacktestResponse, tags=["webserver", "backtest"])
|
||||
def api_backtest_abort():
|
||||
if not ApiBG.bgtask_running:
|
||||
return {
|
||||
@@ -248,7 +250,7 @@ def api_backtest_abort():
|
||||
"progress": 0,
|
||||
"status_msg": "Backtest ended",
|
||||
}
|
||||
ApiBG.bt['bt'].abort = True
|
||||
ApiBG.bt["bt"].abort = True
|
||||
return {
|
||||
"status": "stopping",
|
||||
"running": False,
|
||||
@@ -258,24 +260,26 @@ def api_backtest_abort():
|
||||
}
|
||||
|
||||
|
||||
@router.get('/backtest/history', response_model=List[BacktestHistoryEntry],
|
||||
tags=['webserver', 'backtest'])
|
||||
@router.get(
|
||||
"/backtest/history", response_model=List[BacktestHistoryEntry], tags=["webserver", "backtest"]
|
||||
)
|
||||
def api_backtest_history(config=Depends(get_config)):
|
||||
# Get backtest result history, read from metadata files
|
||||
return get_backtest_resultlist(config['user_data_dir'] / 'backtest_results')
|
||||
return get_backtest_resultlist(config["user_data_dir"] / "backtest_results")
|
||||
|
||||
|
||||
@router.get('/backtest/history/result', response_model=BacktestResponse,
|
||||
tags=['webserver', 'backtest'])
|
||||
@router.get(
|
||||
"/backtest/history/result", response_model=BacktestResponse, tags=["webserver", "backtest"]
|
||||
)
|
||||
def api_backtest_history_result(filename: str, strategy: str, config=Depends(get_config)):
|
||||
# Get backtest result history, read from metadata files
|
||||
bt_results_base: Path = config['user_data_dir'] / 'backtest_results'
|
||||
fn = (bt_results_base / filename).with_suffix('.json')
|
||||
bt_results_base: Path = config["user_data_dir"] / "backtest_results"
|
||||
fn = (bt_results_base / filename).with_suffix(".json")
|
||||
|
||||
results: Dict[str, Any] = {
|
||||
'metadata': {},
|
||||
'strategy': {},
|
||||
'strategy_comparison': [],
|
||||
"metadata": {},
|
||||
"strategy": {},
|
||||
"strategy_comparison": [],
|
||||
}
|
||||
if not is_file_in_dir(fn, bt_results_base):
|
||||
raise HTTPException(status_code=404, detail="File not found.")
|
||||
@@ -290,33 +294,38 @@ def api_backtest_history_result(filename: str, strategy: str, config=Depends(get
|
||||
}
|
||||
|
||||
|
||||
@router.delete('/backtest/history/{file}', response_model=List[BacktestHistoryEntry],
|
||||
tags=['webserver', 'backtest'])
|
||||
@router.delete(
|
||||
"/backtest/history/{file}",
|
||||
response_model=List[BacktestHistoryEntry],
|
||||
tags=["webserver", "backtest"],
|
||||
)
|
||||
def api_delete_backtest_history_entry(file: str, 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')
|
||||
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.")
|
||||
|
||||
delete_backtest_result(file_abs)
|
||||
return get_backtest_resultlist(config['user_data_dir'] / 'backtest_results')
|
||||
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)):
|
||||
@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')
|
||||
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
|
||||
}
|
||||
content = {"notes": body.notes}
|
||||
try:
|
||||
update_backtest_metadata(file_abs, body.strategy, content)
|
||||
except ValueError as e:
|
||||
@@ -325,18 +334,21 @@ def api_update_backtest_history_entry(file: str, body: BacktestMetadataUpdate,
|
||||
return get_backtest_result(file_abs)
|
||||
|
||||
|
||||
@router.get('/backtest/history/{file}/market_change', response_model=BacktestMarketChange,
|
||||
tags=['webserver', 'backtest'])
|
||||
@router.get(
|
||||
"/backtest/history/{file}/market_change",
|
||||
response_model=BacktestMarketChange,
|
||||
tags=["webserver", "backtest"],
|
||||
)
|
||||
def api_get_backtest_market_change(file: str, config=Depends(get_config)):
|
||||
bt_results_base: Path = config['user_data_dir'] / 'backtest_results'
|
||||
file_abs = (bt_results_base / f"{file}_market_change").with_suffix('.feather')
|
||||
bt_results_base: Path = config["user_data_dir"] / "backtest_results"
|
||||
file_abs = (bt_results_base / f"{file}_market_change").with_suffix(".feather")
|
||||
# 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.")
|
||||
df = get_backtest_market_change(file_abs)
|
||||
|
||||
return {
|
||||
'columns': df.columns.tolist(),
|
||||
'data': df.values.tolist(),
|
||||
'length': len(df),
|
||||
"columns": df.columns.tolist(),
|
||||
"data": df.values.tolist(),
|
||||
"length": len(df),
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user