Merge pull request #6622 from freqtrade/short_plot

Short plot
This commit is contained in:
Matthias 2022-04-01 09:18:37 +02:00 committed by GitHub
commit d1ea5ea856
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 58 additions and 53 deletions

View File

@ -276,10 +276,6 @@ def plot_config(self):
!!! Note "Trade position adjustments"
If `position_adjustment_enable` / `adjust_trade_position()` is used, the trade initial buy price is averaged over multiple orders and the trade start price will most likely appear outside the candle range.
!!! Note "Futures / Margin trading"
`plot-dataframe` does not support Futures / short trades, so these trades will simply be missing, and it's unlikely we'll be adding this functionality to this command.
Please use freqUI instead by starting freqtrade in [webserver mode](utils.md#webserver-mode) and use the Chart page to plot your dataframe.
## Plot profit
![plot-profit](assets/plot-profit.png)

View File

@ -1,6 +1,6 @@
import logging
from pathlib import Path
from typing import Any, Dict, List
from typing import Any, Dict, List, Optional
import pandas as pd
@ -11,6 +11,7 @@ from freqtrade.data.btanalysis import (analyze_trade_parallelism, calculate_max_
from freqtrade.data.converter import trim_dataframe
from freqtrade.data.dataprovider import DataProvider
from freqtrade.data.history import get_timerange, load_data
from freqtrade.enums import CandleType
from freqtrade.exceptions import OperationalException
from freqtrade.exchange import timeframe_to_prev_date, timeframe_to_seconds
from freqtrade.misc import pair_to_filename
@ -52,6 +53,7 @@ def init_plotscript(config, markets: List, startup_candles: int = 0):
timerange=timerange,
startup_candles=startup_candles,
data_format=config.get('dataformat_ohlcv', 'json'),
candle_type=config.get('candle_type_def', CandleType.SPOT)
)
if startup_candles and data:
@ -385,6 +387,35 @@ def add_areas(fig, row: int, data: pd.DataFrame, indicators) -> make_subplots:
return fig
def create_scatter(
data,
column_name,
color,
direction
) -> Optional[go.Scatter]:
if column_name in data.columns:
df_short = data[data[column_name] == 1]
if len(df_short) > 0:
shorts = go.Scatter(
x=df_short.date,
y=df_short.close,
mode='markers',
name=column_name,
marker=dict(
symbol=f"triangle-{direction}-dot",
size=9,
line=dict(width=1),
color=color,
)
)
return shorts
else:
logger.warning(f"No {column_name}-signals found.")
return None
def generate_candlestick_graph(pair: str, data: pd.DataFrame, trades: pd.DataFrame = None, *,
indicators1: List[str] = [],
indicators2: List[str] = [],
@ -431,43 +462,15 @@ def generate_candlestick_graph(pair: str, data: pd.DataFrame, trades: pd.DataFra
)
fig.add_trace(candles, 1, 1)
if 'enter_long' in data.columns:
df_buy = data[data['enter_long'] == 1]
if len(df_buy) > 0:
buys = go.Scatter(
x=df_buy.date,
y=df_buy.close,
mode='markers',
name='buy',
marker=dict(
symbol='triangle-up-dot',
size=9,
line=dict(width=1),
color='green',
)
)
fig.add_trace(buys, 1, 1)
else:
logger.warning("No buy-signals found.")
longs = create_scatter(data, 'enter_long', 'green', 'up')
exit_longs = create_scatter(data, 'exit_long', 'red', 'down')
shorts = create_scatter(data, 'enter_short', 'blue', 'down')
exit_shorts = create_scatter(data, 'exit_short', 'violet', 'up')
for scatter in [longs, exit_longs, shorts, exit_shorts]:
if scatter:
fig.add_trace(scatter, 1, 1)
if 'exit_long' in data.columns:
df_sell = data[data['exit_long'] == 1]
if len(df_sell) > 0:
sells = go.Scatter(
x=df_sell.date,
y=df_sell.close,
mode='markers',
name='sell',
marker=dict(
symbol='triangle-down-dot',
size=9,
line=dict(width=1),
color='red',
)
)
fig.add_trace(sells, 1, 1)
else:
logger.warning("No sell-signals found.")
# Add Bollinger Bands
fig = plot_area(fig, 1, data, 'bb_lowerband', 'bb_upperband',
label="Bollinger Band")

View File

@ -18,7 +18,8 @@ from freqtrade import __version__
from freqtrade.configuration.timerange import TimeRange
from freqtrade.constants import CANCEL_REASON, DATETIME_PRINT_FORMAT
from freqtrade.data.history import load_data
from freqtrade.enums import ExitCheckTuple, ExitType, SignalDirection, State, TradingMode
from freqtrade.enums import (CandleType, ExitCheckTuple, ExitType, SignalDirection, State,
TradingMode)
from freqtrade.exceptions import ExchangeError, PricingError
from freqtrade.exchange import timeframe_to_minutes, timeframe_to_msecs
from freqtrade.loggers import bufferHandler
@ -1057,6 +1058,7 @@ class RPC:
timeframe=timeframe,
timerange=timerange_parsed,
data_format=config.get('dataformat_ohlcv', 'json'),
candle_type=config.get('candle_type_def', CandleType.SPOT)
)
if pair not in _data:
raise RPCException(f"No data for {pair}, {timeframe} in {timerange} found.")

View File

@ -202,6 +202,8 @@ def test_generate_candlestick_graph_no_signals_no_trades(default_conf, mocker, t
datadir=testdatadir, timerange=timerange)
data['enter_long'] = 0
data['exit_long'] = 0
data['enter_short'] = 0
data['exit_short'] = 0
indicators1 = []
indicators2 = []
@ -222,8 +224,10 @@ def test_generate_candlestick_graph_no_signals_no_trades(default_conf, mocker, t
assert row_mock.call_count == 2
assert trades_mock.call_count == 1
assert log_has("No buy-signals found.", caplog)
assert log_has("No sell-signals found.", caplog)
assert log_has("No enter_long-signals found.", caplog)
assert log_has("No exit_long-signals found.", caplog)
assert log_has("No enter_short-signals found.", caplog)
assert log_has("No exit_short-signals found.", caplog)
def test_generate_candlestick_graph_no_trades(default_conf, mocker, testdatadir):
@ -249,7 +253,7 @@ def test_generate_candlestick_graph_no_trades(default_conf, mocker, testdatadir)
assert fig.layout.title.text == pair
figure = fig.layout.figure
assert len(figure.data) == 6
assert len(figure.data) == 8
# Candlesticks are plotted first
candles = find_trace_in_fig_data(figure.data, "Price")
assert isinstance(candles, go.Candlestick)
@ -257,15 +261,15 @@ def test_generate_candlestick_graph_no_trades(default_conf, mocker, testdatadir)
volume = find_trace_in_fig_data(figure.data, "Volume")
assert isinstance(volume, go.Bar)
buy = find_trace_in_fig_data(figure.data, "buy")
assert isinstance(buy, go.Scatter)
# All entry-signals should be plotted
assert int(data['enter_long'].sum()) == len(buy.x)
enter_long = find_trace_in_fig_data(figure.data, "enter_long")
assert isinstance(enter_long, go.Scatter)
# All buy-signals should be plotted
assert int(data['enter_long'].sum()) == len(enter_long.x)
sell = find_trace_in_fig_data(figure.data, "sell")
assert isinstance(sell, go.Scatter)
# All entry-signals should be plotted
assert int(data['exit_long'].sum()) == len(sell.x)
exit_long = find_trace_in_fig_data(figure.data, "exit_long")
assert isinstance(exit_long, go.Scatter)
# All buy-signals should be plotted
assert int(data['exit_long'].sum()) == len(exit_long.x)
assert find_trace_in_fig_data(figure.data, "Bollinger Band")