mirror of
https://github.com/freqtrade/freqtrade.git
synced 2024-11-10 10:21:59 +00:00
Merge pull request #9407 from stash86/bt-metrics
add entries, exits, and mix_tags API endpoints
This commit is contained in:
commit
da647735b6
|
@ -141,6 +141,9 @@ python3 scripts/rest_client.py --config rest_config.json <command> [optional par
|
||||||
| `logs` | Shows last log messages.
|
| `logs` | Shows last log messages.
|
||||||
| `status` | Lists all open trades.
|
| `status` | Lists all open trades.
|
||||||
| `count` | Displays number of trades used and available.
|
| `count` | Displays number of trades used and available.
|
||||||
|
| `entries [pair]` | Shows profit statistics for each enter tags for given pair (or all pairs if pair isn't given). Pair is optional.
|
||||||
|
| `exits [pair]` | Shows profit statistics for each exit reasons for given pair (or all pairs if pair isn't given). Pair is optional.
|
||||||
|
| `mix_tags [pair]` | Shows profit statistics for each combinations of enter tag + exit reasons for given pair (or all pairs if pair isn't given). Pair is optional.
|
||||||
| `locks` | Displays currently locked pairs.
|
| `locks` | Displays currently locked pairs.
|
||||||
| `delete_lock <lock_id>` | Deletes (disables) the lock by id.
|
| `delete_lock <lock_id>` | Deletes (disables) the lock by id.
|
||||||
| `profit` | Display a summary of your profit/loss from close trades and some stats about your performance.
|
| `profit` | Display a summary of your profit/loss from close trades and some stats about your performance.
|
||||||
|
|
|
@ -95,6 +95,30 @@ class Count(BaseModel):
|
||||||
total_stake: float
|
total_stake: float
|
||||||
|
|
||||||
|
|
||||||
|
class Entry(BaseModel):
|
||||||
|
enter_tag: str
|
||||||
|
profit_ratio: float
|
||||||
|
profit_pct: float
|
||||||
|
profit_abs: float
|
||||||
|
count: int
|
||||||
|
|
||||||
|
|
||||||
|
class Exit(BaseModel):
|
||||||
|
exit_reason: str
|
||||||
|
profit_ratio: float
|
||||||
|
profit_pct: float
|
||||||
|
profit_abs: float
|
||||||
|
count: int
|
||||||
|
|
||||||
|
|
||||||
|
class MixTag(BaseModel):
|
||||||
|
mix_tag: str
|
||||||
|
profit: float
|
||||||
|
profit_pct: float
|
||||||
|
profit_abs: float
|
||||||
|
count: int
|
||||||
|
|
||||||
|
|
||||||
class PerformanceEntry(BaseModel):
|
class PerformanceEntry(BaseModel):
|
||||||
pair: str
|
pair: str
|
||||||
profit: float
|
profit: float
|
||||||
|
|
|
@ -12,15 +12,15 @@ from freqtrade.exceptions import OperationalException
|
||||||
from freqtrade.rpc import RPC
|
from freqtrade.rpc import RPC
|
||||||
from freqtrade.rpc.api_server.api_schemas import (AvailablePairs, Balances, BlacklistPayload,
|
from freqtrade.rpc.api_server.api_schemas import (AvailablePairs, Balances, BlacklistPayload,
|
||||||
BlacklistResponse, Count, DailyWeeklyMonthly,
|
BlacklistResponse, Count, DailyWeeklyMonthly,
|
||||||
DeleteLockRequest, DeleteTrade,
|
DeleteLockRequest, DeleteTrade, Entry,
|
||||||
ExchangeListResponse, ForceEnterPayload,
|
ExchangeListResponse, Exit, ForceEnterPayload,
|
||||||
ForceEnterResponse, ForceExitPayload,
|
ForceEnterResponse, ForceExitPayload,
|
||||||
FreqAIModelListResponse, Health, Locks, Logs,
|
FreqAIModelListResponse, Health, Locks, Logs,
|
||||||
OpenTradeSchema, PairHistory, PerformanceEntry,
|
MixTag, OpenTradeSchema, PairHistory,
|
||||||
Ping, PlotConfig, Profit, ResultMsg, ShowConfig,
|
PerformanceEntry, Ping, PlotConfig, Profit,
|
||||||
Stats, StatusMsg, StrategyListResponse,
|
ResultMsg, ShowConfig, Stats, StatusMsg,
|
||||||
StrategyResponse, SysInfo, Version,
|
StrategyListResponse, StrategyResponse, SysInfo,
|
||||||
WhitelistResponse)
|
Version, WhitelistResponse)
|
||||||
from freqtrade.rpc.api_server.deps import get_config, get_exchange, get_rpc, get_rpc_optional
|
from freqtrade.rpc.api_server.deps import get_config, get_exchange, get_rpc, get_rpc_optional
|
||||||
from freqtrade.rpc.rpc import RPCException
|
from freqtrade.rpc.rpc import RPCException
|
||||||
|
|
||||||
|
@ -52,7 +52,8 @@ logger = logging.getLogger(__name__)
|
||||||
# 2.31: new /backtest/history/ delete endpoint
|
# 2.31: new /backtest/history/ delete endpoint
|
||||||
# 2.32: new /backtest/history/ patch endpoint
|
# 2.32: new /backtest/history/ patch endpoint
|
||||||
# 2.33: Additional weekly/monthly metrics
|
# 2.33: Additional weekly/monthly metrics
|
||||||
API_VERSION = 2.33
|
# 2.34: new entries/exits/mix_tags endpoints
|
||||||
|
API_VERSION = 2.34
|
||||||
|
|
||||||
# Public API, requires no auth.
|
# Public API, requires no auth.
|
||||||
router_public = APIRouter()
|
router_public = APIRouter()
|
||||||
|
@ -83,6 +84,21 @@ def count(rpc: RPC = Depends(get_rpc)):
|
||||||
return rpc._rpc_count()
|
return rpc._rpc_count()
|
||||||
|
|
||||||
|
|
||||||
|
@router.get('/entries', response_model=List[Entry], tags=['info'])
|
||||||
|
def entries(pair: Optional[str] = None, rpc: RPC = Depends(get_rpc)):
|
||||||
|
return rpc._rpc_enter_tag_performance(pair)
|
||||||
|
|
||||||
|
|
||||||
|
@router.get('/exits', response_model=List[Exit], tags=['info'])
|
||||||
|
def exits(pair: Optional[str] = None, rpc: RPC = Depends(get_rpc)):
|
||||||
|
return rpc._rpc_exit_reason_performance(pair)
|
||||||
|
|
||||||
|
|
||||||
|
@router.get('/mix_tags', response_model=List[MixTag], tags=['info'])
|
||||||
|
def mix_tags(pair: Optional[str] = None, rpc: RPC = Depends(get_rpc)):
|
||||||
|
return rpc._rpc_mix_tag_performance(pair)
|
||||||
|
|
||||||
|
|
||||||
@router.get('/performance', response_model=List[PerformanceEntry], tags=['info'])
|
@router.get('/performance', response_model=List[PerformanceEntry], tags=['info'])
|
||||||
def performance(rpc: RPC = Depends(get_rpc)):
|
def performance(rpc: RPC = Depends(get_rpc)):
|
||||||
return rpc._rpc_performance()
|
return rpc._rpc_performance()
|
||||||
|
|
|
@ -112,6 +112,30 @@ class FtRestClient:
|
||||||
"""
|
"""
|
||||||
return self._get("count")
|
return self._get("count")
|
||||||
|
|
||||||
|
def entries(self, pair=None):
|
||||||
|
"""Returns List of dicts containing all Trades, based on buy tag performance
|
||||||
|
Can either be average for all pairs or a specific pair provided
|
||||||
|
|
||||||
|
:return: json object
|
||||||
|
"""
|
||||||
|
return self._get("entries", params={"pair": pair} if pair else None)
|
||||||
|
|
||||||
|
def exits(self, pair=None):
|
||||||
|
"""Returns List of dicts containing all Trades, based on exit reason performance
|
||||||
|
Can either be average for all pairs or a specific pair provided
|
||||||
|
|
||||||
|
:return: json object
|
||||||
|
"""
|
||||||
|
return self._get("exits", params={"pair": pair} if pair else None)
|
||||||
|
|
||||||
|
def mix_tags(self, pair=None):
|
||||||
|
"""Returns List of dicts containing all Trades, based on entry_tag + exit_reason performance
|
||||||
|
Can either be average for all pairs or a specific pair provided
|
||||||
|
|
||||||
|
:return: json object
|
||||||
|
"""
|
||||||
|
return self._get("mix_tags", params={"pair": pair} if pair else None)
|
||||||
|
|
||||||
def locks(self):
|
def locks(self):
|
||||||
"""Return current locks
|
"""Return current locks
|
||||||
|
|
||||||
|
|
|
@ -1063,6 +1063,63 @@ def test_api_performance(botclient, fee):
|
||||||
'profit_ratio': -0.05570419, 'profit_abs': -0.1150375}]
|
'profit_ratio': -0.05570419, 'profit_abs': -0.1150375}]
|
||||||
|
|
||||||
|
|
||||||
|
def test_api_entries(botclient, fee):
|
||||||
|
ftbot, client = botclient
|
||||||
|
patch_get_signal(ftbot)
|
||||||
|
# Empty
|
||||||
|
rc = client_get(client, f"{BASE_URI}/entries")
|
||||||
|
assert_response(rc)
|
||||||
|
assert len(rc.json()) == 0
|
||||||
|
|
||||||
|
create_mock_trades(fee)
|
||||||
|
rc = client_get(client, f"{BASE_URI}/entries")
|
||||||
|
assert_response(rc)
|
||||||
|
response = rc.json()
|
||||||
|
assert len(response) == 2
|
||||||
|
resp = response[0]
|
||||||
|
assert resp['enter_tag'] == 'TEST1'
|
||||||
|
assert resp['count'] == 1
|
||||||
|
assert resp['profit_pct'] == 0.5
|
||||||
|
|
||||||
|
|
||||||
|
def test_api_exits(botclient, fee):
|
||||||
|
ftbot, client = botclient
|
||||||
|
patch_get_signal(ftbot)
|
||||||
|
# Empty
|
||||||
|
rc = client_get(client, f"{BASE_URI}/exits")
|
||||||
|
assert_response(rc)
|
||||||
|
assert len(rc.json()) == 0
|
||||||
|
|
||||||
|
create_mock_trades(fee)
|
||||||
|
rc = client_get(client, f"{BASE_URI}/exits")
|
||||||
|
assert_response(rc)
|
||||||
|
response = rc.json()
|
||||||
|
assert len(response) == 2
|
||||||
|
resp = response[0]
|
||||||
|
assert resp['exit_reason'] == 'sell_signal'
|
||||||
|
assert resp['count'] == 1
|
||||||
|
assert resp['profit_pct'] == 0.5
|
||||||
|
|
||||||
|
|
||||||
|
def test_api_mix_tag(botclient, fee):
|
||||||
|
ftbot, client = botclient
|
||||||
|
patch_get_signal(ftbot)
|
||||||
|
# Empty
|
||||||
|
rc = client_get(client, f"{BASE_URI}/mix_tags")
|
||||||
|
assert_response(rc)
|
||||||
|
assert len(rc.json()) == 0
|
||||||
|
|
||||||
|
create_mock_trades(fee)
|
||||||
|
rc = client_get(client, f"{BASE_URI}/mix_tags")
|
||||||
|
assert_response(rc)
|
||||||
|
response = rc.json()
|
||||||
|
assert len(response) == 2
|
||||||
|
resp = response[0]
|
||||||
|
assert resp['mix_tag'] == 'TEST1 sell_signal'
|
||||||
|
assert resp['count'] == 1
|
||||||
|
assert resp['profit_pct'] == 0.5
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
'is_short,current_rate,open_trade_value',
|
'is_short,current_rate,open_trade_value',
|
||||||
[(True, 1.098e-05, 15.0911775),
|
[(True, 1.098e-05, 15.0911775),
|
||||||
|
|
Loading…
Reference in New Issue
Block a user