diff --git a/freqtrade/rpc/api_server/api_schemas.py b/freqtrade/rpc/api_server/api_schemas.py index 1b4d46e79..4e20a0f9d 100644 --- a/freqtrade/rpc/api_server/api_schemas.py +++ b/freqtrade/rpc/api_server/api_schemas.py @@ -496,6 +496,12 @@ class PairCandlesRequest(BaseModel): columns: Optional[List[str]] = None +class PairHistoryRequest(PairCandlesRequest): + timerange: str + strategy: str + freqaimodel: Optional[str] = None + + class PairHistory(BaseModel): strategy: str pair: str diff --git a/freqtrade/rpc/api_server/api_v1.py b/freqtrade/rpc/api_server/api_v1.py index d4c2d80cb..2d3ba32fc 100644 --- a/freqtrade/rpc/api_server/api_v1.py +++ b/freqtrade/rpc/api_server/api_v1.py @@ -17,11 +17,11 @@ from freqtrade.rpc.api_server.api_schemas import (AvailablePairs, Balances, Blac ForceEnterResponse, ForceExitPayload, FreqAIModelListResponse, Health, Locks, LocksPayload, Logs, MixTag, OpenTradeSchema, - PairCandlesRequest, PairHistory, PerformanceEntry, - Ping, PlotConfig, Profit, ResultMsg, ShowConfig, - Stats, StatusMsg, StrategyListResponse, - StrategyResponse, SysInfo, Version, - WhitelistResponse) + PairCandlesRequest, PairHistory, + PairHistoryRequest, PerformanceEntry, Ping, + PlotConfig, Profit, ResultMsg, ShowConfig, Stats, + StatusMsg, StrategyListResponse, StrategyResponse, + SysInfo, Version, WhitelistResponse) from freqtrade.rpc.api_server.deps import get_config, get_exchange, get_rpc, get_rpc_optional from freqtrade.rpc.rpc import RPCException @@ -321,6 +321,24 @@ def pair_history(pair: str, timeframe: str, timerange: str, strategy: str, raise HTTPException(status_code=502, detail=str(e)) +@router.post('/pair_history', response_model=PairHistory, tags=['candle data']) +def pair_history_filtered(payload: PairHistoryRequest, + config=Depends(get_config), exchange=Depends(get_exchange)): + # The initial call to this endpoint can be slow, as it may need to initialize + # the exchange class. + config = deepcopy(config) + config.update({ + 'strategy': payload.strategy, + 'timerange': payload.timerange, + 'freqaimodel': payload.freqaimodel if payload.freqaimodel else config.get('freqaimodel'), + }) + try: + return RPC._rpc_analysed_history_full( + config, payload.pair, payload.timeframe, exchange, payload.columns) + except Exception as e: + raise HTTPException(status_code=502, detail=str(e)) + + @router.get('/plot_config', response_model=PlotConfig, tags=['candle data']) def plot_config(strategy: Optional[str] = None, config=Depends(get_config), rpc: Optional[RPC] = Depends(get_rpc_optional)): diff --git a/tests/rpc/test_rpc_apiserver.py b/tests/rpc/test_rpc_apiserver.py index 13d91d494..6fae4aaee 100644 --- a/tests/rpc/test_rpc_apiserver.py +++ b/tests/rpc/test_rpc_apiserver.py @@ -1654,33 +1654,50 @@ def test_api_pair_history(botclient, tmp_path, mocker): assert_response(rc, 502) # Working - rc = client_get(client, - f"{BASE_URI}/pair_history?pair=UNITTEST%2FBTC&timeframe={timeframe}" - f"&timerange=20180111-20180112&strategy={CURRENT_TEST_STRATEGY}") - assert_response(rc, 200) - result = rc.json() - assert result['length'] == 289 - assert len(result['data']) == result['length'] - assert 'columns' in result - assert 'data' in result - data = result['data'] - assert len(data) == 289 - # analyzed DF has 30 columns - assert len(result['columns']) == 30 - assert len(data[0]) == 30 - date_col_idx = [idx for idx, c in enumerate(result['columns']) if c == 'date'][0] - rsi_col_idx = [idx for idx, c in enumerate(result['columns']) if c == 'rsi'][0] + for call in ('get', 'post'): + if call == 'get': + rc = client_get(client, + f"{BASE_URI}/pair_history?pair=UNITTEST%2FBTC&timeframe={timeframe}" + f"&timerange=20180111-20180112&strategy={CURRENT_TEST_STRATEGY}") + else: + rc = client_post( + client, + f"{BASE_URI}/pair_history", + data={ + "pair": "UNITTEST/BTC", + "timeframe": timeframe, + "timerange": "20180111-20180112", + "strategy": CURRENT_TEST_STRATEGY, + "columns": ['rsi', 'fastd', 'fastk'], + }) - assert data[0][date_col_idx] == '2018-01-11T00:00:00Z' - assert data[0][rsi_col_idx] is not None - assert data[0][rsi_col_idx] > 0 - assert lfm.call_count == 1 - assert result['pair'] == 'UNITTEST/BTC' - assert result['strategy'] == CURRENT_TEST_STRATEGY - assert result['data_start'] == '2018-01-11 00:00:00+00:00' - assert result['data_start_ts'] == 1515628800000 - assert result['data_stop'] == '2018-01-12 00:00:00+00:00' - assert result['data_stop_ts'] == 1515715200000 + assert_response(rc, 200) + result = rc.json() + assert result['length'] == 289 + assert len(result['data']) == result['length'] + assert 'columns' in result + assert 'data' in result + data = result['data'] + assert len(data) == 289 + col_count = 30 if call == 'get' else 18 + # analyzed DF has 30 columns + assert len(result['columns']) == col_count + assert len(result['all_columns']) == 25 + assert len(data[0]) == col_count + date_col_idx = [idx for idx, c in enumerate(result['columns']) if c == 'date'][0] + rsi_col_idx = [idx for idx, c in enumerate(result['columns']) if c == 'rsi'][0] + + assert data[0][date_col_idx] == '2018-01-11T00:00:00Z' + assert data[0][rsi_col_idx] is not None + assert data[0][rsi_col_idx] > 0 + assert lfm.call_count == 1 + assert result['pair'] == 'UNITTEST/BTC' + assert result['strategy'] == CURRENT_TEST_STRATEGY + assert result['data_start'] == '2018-01-11 00:00:00+00:00' + assert result['data_start_ts'] == 1515628800000 + assert result['data_stop'] == '2018-01-12 00:00:00+00:00' + assert result['data_stop_ts'] == 1515715200000 + lfm.reset_mock() # No data found rc = client_get(client,