Initial commit previous version
This commit is contained in:
parent
f6cdc6d9a2
commit
9b9cdf9e54
17
.gitignore
vendored
17
.gitignore
vendored
@ -1,11 +1,17 @@
|
|||||||
# Freqtrade rules
|
# Freqtrade rules
|
||||||
config*.json
|
config_offline*.json
|
||||||
|
config_realmoney*.json
|
||||||
|
|
||||||
*.sqlite
|
*.sqlite
|
||||||
logfile.txt
|
logfile.txt
|
||||||
user_data/*
|
|
||||||
!user_data/strategy/sample_strategy.py
|
user_data/backtest_results/*
|
||||||
!user_data/notebooks
|
user_data/data/*
|
||||||
|
user_data/hyperopt_results/*
|
||||||
|
user_data/plot/*
|
||||||
user_data/notebooks/*
|
user_data/notebooks/*
|
||||||
|
user_data/hyperopt.lock
|
||||||
|
|
||||||
freqtrade-plot.html
|
freqtrade-plot.html
|
||||||
freqtrade-profit-plot.html
|
freqtrade-profit-plot.html
|
||||||
freqtrade/rpc/api_server/ui/*
|
freqtrade/rpc/api_server/ui/*
|
||||||
@ -95,3 +101,6 @@ target/
|
|||||||
|
|
||||||
#exceptions
|
#exceptions
|
||||||
!*.gitkeep
|
!*.gitkeep
|
||||||
|
|
||||||
|
#annoying and honestly idk
|
||||||
|
.DS_Store
|
||||||
|
106
config_emptybinance_example.json
Normal file
106
config_emptybinance_example.json
Normal file
@ -0,0 +1,106 @@
|
|||||||
|
{
|
||||||
|
"max_open_trades": 20,
|
||||||
|
"stake_currency": "BTC",
|
||||||
|
"stake_amount": 50,
|
||||||
|
"tradable_balance_ratio": 0.99,
|
||||||
|
"fiat_display_currency": "USD",
|
||||||
|
"timeframe": "1m",
|
||||||
|
"dry_run": true,
|
||||||
|
"cancel_open_orders_on_exit": false,
|
||||||
|
"trailing_stop": false,
|
||||||
|
"unfilledtimeout": {
|
||||||
|
"buy": 10,
|
||||||
|
"sell": 30
|
||||||
|
},
|
||||||
|
"bid_strategy": {
|
||||||
|
"ask_last_balance": 0.0,
|
||||||
|
"use_order_book": false,
|
||||||
|
"order_book_top": 1,
|
||||||
|
"check_depth_of_market": {
|
||||||
|
"enabled": false,
|
||||||
|
"bids_to_ask_delta": 1
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"ask_strategy": {
|
||||||
|
"use_order_book": false,
|
||||||
|
"order_book_min": 1,
|
||||||
|
"order_book_max": 9,
|
||||||
|
"use_sell_signal": true,
|
||||||
|
"sell_profit_only": false,
|
||||||
|
"ignore_roi_if_buy_signal": false
|
||||||
|
},
|
||||||
|
"exchange": {
|
||||||
|
"name": "binance",
|
||||||
|
"key": "m46Wzbo7jE8ERx195Maf4BiDotYpV2GB6uLDXC82Hnp9adtnW13rEv3flwad1Ah4",
|
||||||
|
"secret": "zn5D6EsGK7nQ4Xrnr5d2CZjWdiNadNUK3j4IGcHDygioMhOM9Emd0v2NSvsKsPJv",
|
||||||
|
"ccxt_config": {
|
||||||
|
"enableRateLimit": true
|
||||||
|
},
|
||||||
|
"ccxt_async_config": {
|
||||||
|
"enableRateLimit": true,
|
||||||
|
"rateLimit": 500
|
||||||
|
},
|
||||||
|
"pair_whitelist": [
|
||||||
|
"ETH/BTC",
|
||||||
|
"LTC/BTC",
|
||||||
|
"ETC/BTC",
|
||||||
|
"XLM/BTC",
|
||||||
|
"ADA/BTC",
|
||||||
|
"XMR/BTC",
|
||||||
|
"BNB/BTC",
|
||||||
|
"QLC/BTC",
|
||||||
|
"KMD/BTC",
|
||||||
|
"WTC/BTC",
|
||||||
|
"TRX/BTC",
|
||||||
|
"XRP/BTC",
|
||||||
|
"EOS/BTC",
|
||||||
|
"NEO/BTC",
|
||||||
|
"LINK/BTC",
|
||||||
|
"ONT/BTC",
|
||||||
|
"XEM/BTC",
|
||||||
|
"ICX/BTC"
|
||||||
|
],
|
||||||
|
"pair_blacklist": [
|
||||||
|
"DOGE/BTC"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"pairlists": [
|
||||||
|
{
|
||||||
|
"method": "StaticPairList"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"edge": {
|
||||||
|
"enabled": false,
|
||||||
|
"process_throttle_secs": 3600,
|
||||||
|
"calculate_since_number_of_days": 7,
|
||||||
|
"allowed_risk": 0.01,
|
||||||
|
"stoploss_range_min": -0.01,
|
||||||
|
"stoploss_range_max": -0.1,
|
||||||
|
"stoploss_range_step": -0.01,
|
||||||
|
"minimum_winrate": 0.60,
|
||||||
|
"minimum_expectancy": 0.20,
|
||||||
|
"min_trade_number": 10,
|
||||||
|
"max_trade_duration_minute": 1440,
|
||||||
|
"remove_pumps": false
|
||||||
|
},
|
||||||
|
"telegram": {
|
||||||
|
"enabled": true,
|
||||||
|
"token": "1080082600:AAHQOQI4oObA1P3Sf9408OJVSlMc7t5pxhI",
|
||||||
|
"chat_id": "1009222459"
|
||||||
|
},
|
||||||
|
"api_server": {
|
||||||
|
"enabled": false,
|
||||||
|
"listen_ip_address": "127.0.0.1",
|
||||||
|
"listen_port": 8080,
|
||||||
|
"verbosity": "info",
|
||||||
|
"jwt_secret_key": "somethingrandom",
|
||||||
|
"username": "",
|
||||||
|
"password": ""
|
||||||
|
},
|
||||||
|
"bot_name": "Tradingbot",
|
||||||
|
"initial_state": "running",
|
||||||
|
"forcebuy_enable": false,
|
||||||
|
"internals": {
|
||||||
|
"process_throttle_secs": 5
|
||||||
|
}
|
||||||
|
}
|
85
freqtrade/optimize/hyperopt_loss_sharpe_trades100.py
Normal file
85
freqtrade/optimize/hyperopt_loss_sharpe_trades100.py
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
"""
|
||||||
|
SharpeHyperOptLossTrades
|
||||||
|
|
||||||
|
This module defines the alternative HyperOptLoss class which can be used for
|
||||||
|
Hyperoptimization.
|
||||||
|
|
||||||
|
The MINIMUM_TRADES and SLIPPAGE_PER_TRADE_RATIO can be altered to whatever you like.
|
||||||
|
The values that make up the maximum trade_grade can be altered as well.
|
||||||
|
"""
|
||||||
|
import math
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
from pandas import DataFrame, date_range
|
||||||
|
|
||||||
|
from freqtrade.optimize.hyperopt import IHyperOptLoss
|
||||||
|
|
||||||
|
|
||||||
|
class SharpeHyperOptLossTrades100(IHyperOptLoss):
|
||||||
|
"""
|
||||||
|
Defines the loss function for hyperopt.
|
||||||
|
|
||||||
|
This implementation uses the Sharpe Ratio Daily calculation and the Trade Grade calculation.
|
||||||
|
"""
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def hyperopt_loss_function(results: DataFrame, trade_count: int,
|
||||||
|
min_date: datetime, max_date: datetime,
|
||||||
|
*args, **kwargs) -> float:
|
||||||
|
"""
|
||||||
|
Objective function, returns smaller number for more optimal results.
|
||||||
|
|
||||||
|
Uses the Sharpe Ratio Daily calculation and the Trade Grade calculation.
|
||||||
|
"""
|
||||||
|
|
||||||
|
# CONSTANTS
|
||||||
|
MINIMUM_TRADES = 100
|
||||||
|
SLIPPAGE_PER_TRADE_RATIO = 0.001
|
||||||
|
NUMERATOR_MAX_TRADEGRADE = 80
|
||||||
|
DENOMINATOR_MAX_TRADEGRADE = 8
|
||||||
|
RESAMPLE_FREQ = '1D'
|
||||||
|
DAYS_IN_YEAR = 365
|
||||||
|
ANNUAL_RISK_FREE_RATE = 0.0
|
||||||
|
|
||||||
|
risk_free_rate = ANNUAL_RISK_FREE_RATE / DAYS_IN_YEAR
|
||||||
|
|
||||||
|
"""
|
||||||
|
Sharpe Ratio Calculation
|
||||||
|
"""
|
||||||
|
# apply slippage per trade to profit_percent
|
||||||
|
results.loc[:, 'profit_percent_after_slippage'] = \
|
||||||
|
results['profit_percent'] - SLIPPAGE_PER_TRADE_RATIO
|
||||||
|
|
||||||
|
# create the index within the min_date and end max_date
|
||||||
|
t_index = date_range(start=min_date, end=max_date, freq=RESAMPLE_FREQ,
|
||||||
|
normalize=True)
|
||||||
|
|
||||||
|
sum_daily = (
|
||||||
|
results.resample(RESAMPLE_FREQ, on='close_time').agg(
|
||||||
|
{"profit_percent_after_slippage": sum}).reindex(t_index).fillna(0)
|
||||||
|
)
|
||||||
|
|
||||||
|
total_profit = sum_daily["profit_percent_after_slippage"] - risk_free_rate
|
||||||
|
expected_returns_mean = total_profit.mean()
|
||||||
|
up_stdev = total_profit.std()
|
||||||
|
|
||||||
|
if up_stdev != 0:
|
||||||
|
sharp_ratio = expected_returns_mean / up_stdev * math.sqrt(DAYS_IN_YEAR)
|
||||||
|
else:
|
||||||
|
# Define high (negative) sharpe ratio to be clear that this is NOT optimal.
|
||||||
|
sharp_ratio = -30.
|
||||||
|
|
||||||
|
"""
|
||||||
|
Trade Grade Calculation
|
||||||
|
This function has a maximum grade of 80/DENOMINATOR_MAX_TRADEGRADE.
|
||||||
|
A minimum of 105 trades.
|
||||||
|
"""
|
||||||
|
|
||||||
|
if trade_count <= (MINIMUM_TRADES + 5):
|
||||||
|
# Define high (negative) trade grade tp be clear that this is NOT optimal
|
||||||
|
trade_grade = -30
|
||||||
|
else:
|
||||||
|
trade_grade = ((1 / (-0.001 * (trade_count - MINIMUM_TRADES))) +
|
||||||
|
NUMERATOR_MAX_TRADEGRADE) / DENOMINATOR_MAX_TRADEGRADE
|
||||||
|
|
||||||
|
return -(sharp_ratio + trade_grade)
|
85
freqtrade/optimize/hyperopt_loss_sharpe_trades1000.py
Normal file
85
freqtrade/optimize/hyperopt_loss_sharpe_trades1000.py
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
"""
|
||||||
|
SharpeHyperOptLossTrades
|
||||||
|
|
||||||
|
This module defines the alternative HyperOptLoss class which can be used for
|
||||||
|
Hyperoptimization.
|
||||||
|
|
||||||
|
The MINIMUM_TRADES and SLIPPAGE_PER_TRADE_RATIO can be altered to whatever you like.
|
||||||
|
The values that make up the maximum trade_grade can be altered as well.
|
||||||
|
"""
|
||||||
|
import math
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
from pandas import DataFrame, date_range
|
||||||
|
|
||||||
|
from freqtrade.optimize.hyperopt import IHyperOptLoss
|
||||||
|
|
||||||
|
|
||||||
|
class SharpeHyperOptLossTrades1000(IHyperOptLoss):
|
||||||
|
"""
|
||||||
|
Defines the loss function for hyperopt.
|
||||||
|
|
||||||
|
This implementation uses the Sharpe Ratio Daily calculation and the Trade Grade calculation.
|
||||||
|
"""
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def hyperopt_loss_function(results: DataFrame, trade_count: int,
|
||||||
|
min_date: datetime, max_date: datetime,
|
||||||
|
*args, **kwargs) -> float:
|
||||||
|
"""
|
||||||
|
Objective function, returns smaller number for more optimal results.
|
||||||
|
|
||||||
|
Uses the Sharpe Ratio Daily calculation and the Trade Grade calculation.
|
||||||
|
"""
|
||||||
|
|
||||||
|
# CONSTANTS
|
||||||
|
MINIMUM_TRADES = 1000
|
||||||
|
SLIPPAGE_PER_TRADE_RATIO = 0.001
|
||||||
|
NUMERATOR_MAX_TRADEGRADE = 80
|
||||||
|
DENOMINATOR_MAX_TRADEGRADE = 8
|
||||||
|
RESAMPLE_FREQ = '1D'
|
||||||
|
DAYS_IN_YEAR = 365
|
||||||
|
ANNUAL_RISK_FREE_RATE = 0.0
|
||||||
|
|
||||||
|
risk_free_rate = ANNUAL_RISK_FREE_RATE / DAYS_IN_YEAR
|
||||||
|
|
||||||
|
"""
|
||||||
|
Sharpe Ratio Calculation
|
||||||
|
"""
|
||||||
|
# apply slippage per trade to profit_percent
|
||||||
|
results.loc[:, 'profit_percent_after_slippage'] = \
|
||||||
|
results['profit_percent'] - SLIPPAGE_PER_TRADE_RATIO
|
||||||
|
|
||||||
|
# create the index within the min_date and end max_date
|
||||||
|
t_index = date_range(start=min_date, end=max_date, freq=RESAMPLE_FREQ,
|
||||||
|
normalize=True)
|
||||||
|
|
||||||
|
sum_daily = (
|
||||||
|
results.resample(RESAMPLE_FREQ, on='close_time').agg(
|
||||||
|
{"profit_percent_after_slippage": sum}).reindex(t_index).fillna(0)
|
||||||
|
)
|
||||||
|
|
||||||
|
total_profit = sum_daily["profit_percent_after_slippage"] - risk_free_rate
|
||||||
|
expected_returns_mean = total_profit.mean()
|
||||||
|
up_stdev = total_profit.std()
|
||||||
|
|
||||||
|
if up_stdev != 0:
|
||||||
|
sharp_ratio = expected_returns_mean / up_stdev * math.sqrt(DAYS_IN_YEAR)
|
||||||
|
else:
|
||||||
|
# Define high (negative) sharpe ratio to be clear that this is NOT optimal.
|
||||||
|
sharp_ratio = -30.
|
||||||
|
|
||||||
|
"""
|
||||||
|
Trade Grade Calculation
|
||||||
|
This function has a maximum grade of 80/DENOMINATOR_MAX_TRADEGRADE.
|
||||||
|
A minimum of 1005 trades.
|
||||||
|
"""
|
||||||
|
|
||||||
|
if trade_count <= (MINIMUM_TRADES + 5):
|
||||||
|
# Define high (negative) trade grade tp be clear that this is NOT optimal
|
||||||
|
trade_grade = -30
|
||||||
|
else:
|
||||||
|
trade_grade = ((1 / (-0.001 * (trade_count - MINIMUM_TRADES))) +
|
||||||
|
NUMERATOR_MAX_TRADEGRADE) / DENOMINATOR_MAX_TRADEGRADE
|
||||||
|
|
||||||
|
return -(sharp_ratio + trade_grade)
|
85
freqtrade/optimize/hyperopt_loss_sharpe_trades20.py
Normal file
85
freqtrade/optimize/hyperopt_loss_sharpe_trades20.py
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
"""
|
||||||
|
SharpeHyperOptLossTrades
|
||||||
|
|
||||||
|
This module defines the alternative HyperOptLoss class which can be used for
|
||||||
|
Hyperoptimization.
|
||||||
|
|
||||||
|
The MINIMUM_TRADES and SLIPPAGE_PER_TRADE_RATIO can be altered to whatever you like.
|
||||||
|
The values that make up the maximum trade_grade can be altered as well.
|
||||||
|
"""
|
||||||
|
import math
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
from pandas import DataFrame, date_range
|
||||||
|
|
||||||
|
from freqtrade.optimize.hyperopt import IHyperOptLoss
|
||||||
|
|
||||||
|
|
||||||
|
class SharpeHyperOptLossTrades20(IHyperOptLoss):
|
||||||
|
"""
|
||||||
|
Defines the loss function for hyperopt.
|
||||||
|
|
||||||
|
This implementation uses the Sharpe Ratio Daily calculation and the Trade Grade calculation.
|
||||||
|
"""
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def hyperopt_loss_function(results: DataFrame, trade_count: int,
|
||||||
|
min_date: datetime, max_date: datetime,
|
||||||
|
*args, **kwargs) -> float:
|
||||||
|
"""
|
||||||
|
Objective function, returns smaller number for more optimal results.
|
||||||
|
|
||||||
|
Uses the Sharpe Ratio Daily calculation and the Trade Grade calculation.
|
||||||
|
"""
|
||||||
|
|
||||||
|
# CONSTANTS
|
||||||
|
MINIMUM_TRADES = 20
|
||||||
|
SLIPPAGE_PER_TRADE_RATIO = 0.001
|
||||||
|
NUMERATOR_MAX_TRADEGRADE = 80
|
||||||
|
DENOMINATOR_MAX_TRADEGRADE = 8
|
||||||
|
RESAMPLE_FREQ = '1D'
|
||||||
|
DAYS_IN_YEAR = 365
|
||||||
|
ANNUAL_RISK_FREE_RATE = 0.0
|
||||||
|
|
||||||
|
risk_free_rate = ANNUAL_RISK_FREE_RATE / DAYS_IN_YEAR
|
||||||
|
|
||||||
|
"""
|
||||||
|
Sharpe Ratio Calculation
|
||||||
|
"""
|
||||||
|
# apply slippage per trade to profit_percent
|
||||||
|
results.loc[:, 'profit_percent_after_slippage'] = \
|
||||||
|
results['profit_percent'] - SLIPPAGE_PER_TRADE_RATIO
|
||||||
|
|
||||||
|
# create the index within the min_date and end max_date
|
||||||
|
t_index = date_range(start=min_date, end=max_date, freq=RESAMPLE_FREQ,
|
||||||
|
normalize=True)
|
||||||
|
|
||||||
|
sum_daily = (
|
||||||
|
results.resample(RESAMPLE_FREQ, on='close_time').agg(
|
||||||
|
{"profit_percent_after_slippage": sum}).reindex(t_index).fillna(0)
|
||||||
|
)
|
||||||
|
|
||||||
|
total_profit = sum_daily["profit_percent_after_slippage"] - risk_free_rate
|
||||||
|
expected_returns_mean = total_profit.mean()
|
||||||
|
up_stdev = total_profit.std()
|
||||||
|
|
||||||
|
if up_stdev != 0:
|
||||||
|
sharp_ratio = expected_returns_mean / up_stdev * math.sqrt(DAYS_IN_YEAR)
|
||||||
|
else:
|
||||||
|
# Define high (negative) sharpe ratio to be clear that this is NOT optimal.
|
||||||
|
sharp_ratio = -30.
|
||||||
|
|
||||||
|
"""
|
||||||
|
Trade Grade Calculation
|
||||||
|
This function has a maximum grade of 80/DENOMINATOR_MAX_TRADEGRADE.
|
||||||
|
A minimum of 25 trades.
|
||||||
|
"""
|
||||||
|
|
||||||
|
if trade_count <= (MINIMUM_TRADES + 5):
|
||||||
|
# Define high (negative) trade grade tp be clear that this is NOT optimal
|
||||||
|
trade_grade = -30
|
||||||
|
else:
|
||||||
|
trade_grade = ((1 / (-0.001 * (trade_count - MINIMUM_TRADES))) +
|
||||||
|
NUMERATOR_MAX_TRADEGRADE) / DENOMINATOR_MAX_TRADEGRADE
|
||||||
|
|
||||||
|
return -(sharp_ratio + trade_grade)
|
85
freqtrade/optimize/hyperopt_loss_sharpe_trades250.py
Normal file
85
freqtrade/optimize/hyperopt_loss_sharpe_trades250.py
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
"""
|
||||||
|
SharpeHyperOptLossTrades
|
||||||
|
|
||||||
|
This module defines the alternative HyperOptLoss class which can be used for
|
||||||
|
Hyperoptimization.
|
||||||
|
|
||||||
|
The MINIMUM_TRADES and SLIPPAGE_PER_TRADE_RATIO can be altered to whatever you like.
|
||||||
|
The values that make up the maximum trade_grade can be altered as well.
|
||||||
|
"""
|
||||||
|
import math
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
from pandas import DataFrame, date_range
|
||||||
|
|
||||||
|
from freqtrade.optimize.hyperopt import IHyperOptLoss
|
||||||
|
|
||||||
|
|
||||||
|
class SharpeHyperOptLossTrades250(IHyperOptLoss):
|
||||||
|
"""
|
||||||
|
Defines the loss function for hyperopt.
|
||||||
|
|
||||||
|
This implementation uses the Sharpe Ratio Daily calculation and the Trade Grade calculation.
|
||||||
|
"""
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def hyperopt_loss_function(results: DataFrame, trade_count: int,
|
||||||
|
min_date: datetime, max_date: datetime,
|
||||||
|
*args, **kwargs) -> float:
|
||||||
|
"""
|
||||||
|
Objective function, returns smaller number for more optimal results.
|
||||||
|
|
||||||
|
Uses the Sharpe Ratio Daily calculation and the Trade Grade calculation.
|
||||||
|
"""
|
||||||
|
|
||||||
|
# CONSTANTS
|
||||||
|
MINIMUM_TRADES = 250
|
||||||
|
SLIPPAGE_PER_TRADE_RATIO = 0.001
|
||||||
|
NUMERATOR_MAX_TRADEGRADE = 80
|
||||||
|
DENOMINATOR_MAX_TRADEGRADE = 8
|
||||||
|
RESAMPLE_FREQ = '1D'
|
||||||
|
DAYS_IN_YEAR = 365
|
||||||
|
ANNUAL_RISK_FREE_RATE = 0.0
|
||||||
|
|
||||||
|
risk_free_rate = ANNUAL_RISK_FREE_RATE / DAYS_IN_YEAR
|
||||||
|
|
||||||
|
"""
|
||||||
|
Sharpe Ratio Calculation
|
||||||
|
"""
|
||||||
|
# apply slippage per trade to profit_percent
|
||||||
|
results.loc[:, 'profit_percent_after_slippage'] = \
|
||||||
|
results['profit_percent'] - SLIPPAGE_PER_TRADE_RATIO
|
||||||
|
|
||||||
|
# create the index within the min_date and end max_date
|
||||||
|
t_index = date_range(start=min_date, end=max_date, freq=RESAMPLE_FREQ,
|
||||||
|
normalize=True)
|
||||||
|
|
||||||
|
sum_daily = (
|
||||||
|
results.resample(RESAMPLE_FREQ, on='close_time').agg(
|
||||||
|
{"profit_percent_after_slippage": sum}).reindex(t_index).fillna(0)
|
||||||
|
)
|
||||||
|
|
||||||
|
total_profit = sum_daily["profit_percent_after_slippage"] - risk_free_rate
|
||||||
|
expected_returns_mean = total_profit.mean()
|
||||||
|
up_stdev = total_profit.std()
|
||||||
|
|
||||||
|
if up_stdev != 0:
|
||||||
|
sharp_ratio = expected_returns_mean / up_stdev * math.sqrt(DAYS_IN_YEAR)
|
||||||
|
else:
|
||||||
|
# Define high (negative) sharpe ratio to be clear that this is NOT optimal.
|
||||||
|
sharp_ratio = -30.
|
||||||
|
|
||||||
|
"""
|
||||||
|
Trade Grade Calculation
|
||||||
|
This function has a maximum grade of 80/DENOMINATOR_MAX_TRADEGRADE.
|
||||||
|
A minimum of 255 trades.
|
||||||
|
"""
|
||||||
|
|
||||||
|
if trade_count <= (MINIMUM_TRADES + 5):
|
||||||
|
# Define high (negative) trade grade tp be clear that this is NOT optimal
|
||||||
|
trade_grade = -30
|
||||||
|
else:
|
||||||
|
trade_grade = ((1 / (-0.001 * (trade_count - MINIMUM_TRADES))) +
|
||||||
|
NUMERATOR_MAX_TRADEGRADE) / DENOMINATOR_MAX_TRADEGRADE
|
||||||
|
|
||||||
|
return -(sharp_ratio + trade_grade)
|
85
freqtrade/optimize/hyperopt_loss_sharpe_trades50.py
Normal file
85
freqtrade/optimize/hyperopt_loss_sharpe_trades50.py
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
"""
|
||||||
|
SharpeHyperOptLossTrades
|
||||||
|
|
||||||
|
This module defines the alternative HyperOptLoss class which can be used for
|
||||||
|
Hyperoptimization.
|
||||||
|
|
||||||
|
The MINIMUM_TRADES and SLIPPAGE_PER_TRADE_RATIO can be altered to whatever you like.
|
||||||
|
The values that make up the maximum trade_grade can be altered as well.
|
||||||
|
"""
|
||||||
|
import math
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
from pandas import DataFrame, date_range
|
||||||
|
|
||||||
|
from freqtrade.optimize.hyperopt import IHyperOptLoss
|
||||||
|
|
||||||
|
|
||||||
|
class SharpeHyperOptLossTrades50(IHyperOptLoss):
|
||||||
|
"""
|
||||||
|
Defines the loss function for hyperopt.
|
||||||
|
|
||||||
|
This implementation uses the Sharpe Ratio Daily calculation and the Trade Grade calculation.
|
||||||
|
"""
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def hyperopt_loss_function(results: DataFrame, trade_count: int,
|
||||||
|
min_date: datetime, max_date: datetime,
|
||||||
|
*args, **kwargs) -> float:
|
||||||
|
"""
|
||||||
|
Objective function, returns smaller number for more optimal results.
|
||||||
|
|
||||||
|
Uses the Sharpe Ratio Daily calculation and the Trade Grade calculation.
|
||||||
|
"""
|
||||||
|
|
||||||
|
# CONSTANTS
|
||||||
|
MINIMUM_TRADES = 50
|
||||||
|
SLIPPAGE_PER_TRADE_RATIO = 0.001
|
||||||
|
NUMERATOR_MAX_TRADEGRADE = 80
|
||||||
|
DENOMINATOR_MAX_TRADEGRADE = 8
|
||||||
|
RESAMPLE_FREQ = '1D'
|
||||||
|
DAYS_IN_YEAR = 365
|
||||||
|
ANNUAL_RISK_FREE_RATE = 0.0
|
||||||
|
|
||||||
|
risk_free_rate = ANNUAL_RISK_FREE_RATE / DAYS_IN_YEAR
|
||||||
|
|
||||||
|
"""
|
||||||
|
Sharpe Ratio Calculation
|
||||||
|
"""
|
||||||
|
# apply slippage per trade to profit_percent
|
||||||
|
results.loc[:, 'profit_percent_after_slippage'] = \
|
||||||
|
results['profit_percent'] - SLIPPAGE_PER_TRADE_RATIO
|
||||||
|
|
||||||
|
# create the index within the min_date and end max_date
|
||||||
|
t_index = date_range(start=min_date, end=max_date, freq=RESAMPLE_FREQ,
|
||||||
|
normalize=True)
|
||||||
|
|
||||||
|
sum_daily = (
|
||||||
|
results.resample(RESAMPLE_FREQ, on='close_time').agg(
|
||||||
|
{"profit_percent_after_slippage": sum}).reindex(t_index).fillna(0)
|
||||||
|
)
|
||||||
|
|
||||||
|
total_profit = sum_daily["profit_percent_after_slippage"] - risk_free_rate
|
||||||
|
expected_returns_mean = total_profit.mean()
|
||||||
|
up_stdev = total_profit.std()
|
||||||
|
|
||||||
|
if up_stdev != 0:
|
||||||
|
sharp_ratio = expected_returns_mean / up_stdev * math.sqrt(DAYS_IN_YEAR)
|
||||||
|
else:
|
||||||
|
# Define high (negative) sharpe ratio to be clear that this is NOT optimal.
|
||||||
|
sharp_ratio = -30.
|
||||||
|
|
||||||
|
"""
|
||||||
|
Trade Grade Calculation
|
||||||
|
This function has a maximum grade of 80/DENOMINATOR_MAX_TRADEGRADE.
|
||||||
|
A minimum of 55 trades.
|
||||||
|
"""
|
||||||
|
|
||||||
|
if trade_count <= (MINIMUM_TRADES + 5):
|
||||||
|
# Define high (negative) trade grade tp be clear that this is NOT optimal
|
||||||
|
trade_grade = -30
|
||||||
|
else:
|
||||||
|
trade_grade = ((1 / (-0.001 * (trade_count - MINIMUM_TRADES))) +
|
||||||
|
NUMERATOR_MAX_TRADEGRADE) / DENOMINATOR_MAX_TRADEGRADE
|
||||||
|
|
||||||
|
return -(sharp_ratio + trade_grade)
|
85
freqtrade/optimize/hyperopt_loss_sharpe_trades_custom.py
Normal file
85
freqtrade/optimize/hyperopt_loss_sharpe_trades_custom.py
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
"""
|
||||||
|
SharpeHyperOptLossTrades
|
||||||
|
|
||||||
|
This module defines the alternative HyperOptLoss class which can be used for
|
||||||
|
Hyperoptimization.
|
||||||
|
|
||||||
|
The MINIMUM_TRADES and SLIPPAGE_PER_TRADE_RATIO can be altered to whatever you like.
|
||||||
|
The values that make up the maximum trade_grade can be altered as well.
|
||||||
|
"""
|
||||||
|
import math
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
from pandas import DataFrame, date_range
|
||||||
|
|
||||||
|
from freqtrade.optimize.hyperopt import IHyperOptLoss
|
||||||
|
|
||||||
|
|
||||||
|
class SharpeHyperOptLossTradesCustom(IHyperOptLoss):
|
||||||
|
"""
|
||||||
|
Defines the loss function for hyperopt.
|
||||||
|
|
||||||
|
This implementation uses the Sharpe Ratio Daily calculation and the Trade Grade calculation.
|
||||||
|
"""
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def hyperopt_loss_function(results: DataFrame, trade_count: int,
|
||||||
|
min_date: datetime, max_date: datetime,
|
||||||
|
*args, **kwargs) -> float:
|
||||||
|
"""
|
||||||
|
Objective function, returns smaller number for more optimal results.
|
||||||
|
|
||||||
|
Uses the Sharpe Ratio Daily calculation and the Trade Grade calculation.
|
||||||
|
"""
|
||||||
|
|
||||||
|
# CONSTANTS
|
||||||
|
MINIMUM_TRADES = 0
|
||||||
|
SLIPPAGE_PER_TRADE_RATIO = 0.001
|
||||||
|
NUMERATOR_MAX_TRADEGRADE = 80
|
||||||
|
DENOMINATOR_MAX_TRADEGRADE = 8
|
||||||
|
RESAMPLE_FREQ = '1D'
|
||||||
|
DAYS_IN_YEAR = 365
|
||||||
|
ANNUAL_RISK_FREE_RATE = 0.0
|
||||||
|
|
||||||
|
risk_free_rate = ANNUAL_RISK_FREE_RATE / DAYS_IN_YEAR
|
||||||
|
|
||||||
|
"""
|
||||||
|
Sharpe Ratio Calculation
|
||||||
|
"""
|
||||||
|
# apply slippage per trade to profit_percent
|
||||||
|
results.loc[:, 'profit_percent_after_slippage'] = \
|
||||||
|
results['profit_percent'] - SLIPPAGE_PER_TRADE_RATIO
|
||||||
|
|
||||||
|
# create the index within the min_date and end max_date
|
||||||
|
t_index = date_range(start=min_date, end=max_date, freq=RESAMPLE_FREQ,
|
||||||
|
normalize=True)
|
||||||
|
|
||||||
|
sum_daily = (
|
||||||
|
results.resample(RESAMPLE_FREQ, on='close_time').agg(
|
||||||
|
{"profit_percent_after_slippage": sum}).reindex(t_index).fillna(0)
|
||||||
|
)
|
||||||
|
|
||||||
|
total_profit = sum_daily["profit_percent_after_slippage"] - risk_free_rate
|
||||||
|
expected_returns_mean = total_profit.mean()
|
||||||
|
up_stdev = total_profit.std()
|
||||||
|
|
||||||
|
if up_stdev != 0:
|
||||||
|
sharp_ratio = expected_returns_mean / up_stdev * math.sqrt(DAYS_IN_YEAR)
|
||||||
|
else:
|
||||||
|
# Define high (negative) sharpe ratio to be clear that this is NOT optimal.
|
||||||
|
sharp_ratio = -30.
|
||||||
|
|
||||||
|
"""
|
||||||
|
Trade Grade Calculation
|
||||||
|
This function has a maximum grade of 80/DENOMINATOR_MAX_TRADEGRADE.
|
||||||
|
A minimum of ... trades.
|
||||||
|
"""
|
||||||
|
|
||||||
|
if trade_count <= (MINIMUM_TRADES + 5):
|
||||||
|
# Define high (negative) trade grade tp be clear that this is NOT optimal
|
||||||
|
trade_grade = -30
|
||||||
|
else:
|
||||||
|
trade_grade = ((1 / (-0.001 * (trade_count - MINIMUM_TRADES))) +
|
||||||
|
NUMERATOR_MAX_TRADEGRADE) / DENOMINATOR_MAX_TRADEGRADE
|
||||||
|
|
||||||
|
return -(sharp_ratio + trade_grade)
|
293
user_data/hyperopts/BasicHyperopt.py
Normal file
293
user_data/hyperopts/BasicHyperopt.py
Normal file
@ -0,0 +1,293 @@
|
|||||||
|
# pragma pylint: disable=missing-docstring, invalid-name, pointless-string-statement
|
||||||
|
|
||||||
|
# --- Do not remove these libs ---
|
||||||
|
from functools import reduce
|
||||||
|
from typing import Any, Callable, Dict, List
|
||||||
|
|
||||||
|
import numpy # noqa
|
||||||
|
import pandas # noqa
|
||||||
|
from pandas import DataFrame
|
||||||
|
from skopt.space import Categorical, Dimension, Integer, Real # noqa
|
||||||
|
|
||||||
|
from freqtrade.optimize.hyperopt_interface import IHyperOpt
|
||||||
|
|
||||||
|
# --------------------------------
|
||||||
|
# Add your lib to import here
|
||||||
|
import talib.abstract as ta # noqa
|
||||||
|
import freqtrade.vendor.qtpylib.indicators as qtpylib
|
||||||
|
|
||||||
|
|
||||||
|
class BasicHyperopt(IHyperOpt):
|
||||||
|
"""
|
||||||
|
This is a Hyperopt template to get you started.
|
||||||
|
|
||||||
|
More information in the documentation: https://www.freqtrade.io/en/latest/hyperopt/
|
||||||
|
|
||||||
|
You should:
|
||||||
|
- Add any lib you need to build your hyperopt.
|
||||||
|
|
||||||
|
You must keep:
|
||||||
|
- The prototypes for the methods: populate_indicators, indicator_space, buy_strategy_generator.
|
||||||
|
|
||||||
|
The methods roi_space, generate_roi_table and stoploss_space are not required
|
||||||
|
and are provided by default.
|
||||||
|
However, you may override them if you need 'roi' and 'stoploss' spaces that
|
||||||
|
differ from the defaults offered by Freqtrade.
|
||||||
|
Sample implementation of these methods will be copied to `user_data/hyperopts` when
|
||||||
|
creating the user-data directory using `freqtrade create-userdir --userdir user_data`,
|
||||||
|
or is available online under the following URL:
|
||||||
|
https://github.com/freqtrade/freqtrade/blob/develop/freqtrade/templates/sample_hyperopt_advanced.py.
|
||||||
|
"""
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def populate_indicators(dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||||
|
|
||||||
|
# RSI
|
||||||
|
dataframe['rsi'] = ta.RSI(dataframe)
|
||||||
|
|
||||||
|
# Bollinger Bands stds 2
|
||||||
|
bollinger2 = qtpylib.bollinger_bands(qtpylib.typical_price(dataframe), window=20, stds=2)
|
||||||
|
dataframe['bb_lowerband2'] = bollinger2['lower']
|
||||||
|
dataframe['bb_middleband2'] = bollinger2['mid']
|
||||||
|
dataframe['bb_upperband2'] = bollinger2['upper']
|
||||||
|
|
||||||
|
return dataframe
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def buy_strategy_generator(params: Dict[str, Any]) -> Callable:
|
||||||
|
"""
|
||||||
|
Define the buy strategy parameters to be used by Hyperopt.
|
||||||
|
"""
|
||||||
|
def populate_buy_trend(dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||||
|
"""
|
||||||
|
Buy strategy Hyperopt will build and use.
|
||||||
|
"""
|
||||||
|
conditions = []
|
||||||
|
|
||||||
|
# GUARDS AND TRENDS
|
||||||
|
if params.get('mfi-enabled'):
|
||||||
|
conditions.append(dataframe['mfi'] < params['mfi-value'])
|
||||||
|
if params.get('fastd-enabled'):
|
||||||
|
conditions.append(dataframe['fastd'] < params['fastd-value'])
|
||||||
|
if params.get('adx-enabled'):
|
||||||
|
conditions.append(dataframe['adx'] > params['adx-value'])
|
||||||
|
if params.get('rsi-enabled'):
|
||||||
|
conditions.append(dataframe['rsi'] < params['rsi-value'])
|
||||||
|
|
||||||
|
# TRIGGERS
|
||||||
|
if 'trigger' in params:
|
||||||
|
if params['trigger'] == 'bb_lower':
|
||||||
|
conditions.append(dataframe['close'] < dataframe['bb_lowerband'])
|
||||||
|
if params['trigger'] == 'macd_cross_signal':
|
||||||
|
conditions.append(qtpylib.crossed_above(
|
||||||
|
dataframe['macd'], dataframe['macdsignal']
|
||||||
|
))
|
||||||
|
if params['trigger'] == 'sar_reversal':
|
||||||
|
conditions.append(qtpylib.crossed_above(
|
||||||
|
dataframe['close'], dataframe['sar']
|
||||||
|
))
|
||||||
|
|
||||||
|
# Check that the candle had volume
|
||||||
|
conditions.append(dataframe['volume'] > 0)
|
||||||
|
|
||||||
|
if conditions:
|
||||||
|
dataframe.loc[
|
||||||
|
reduce(lambda x, y: x & y, conditions),
|
||||||
|
'buy'] = 1
|
||||||
|
|
||||||
|
return dataframe
|
||||||
|
|
||||||
|
return populate_buy_trend
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def indicator_space() -> List[Dimension]:
|
||||||
|
"""
|
||||||
|
Define your Hyperopt space for searching buy strategy parameters.
|
||||||
|
"""
|
||||||
|
return [
|
||||||
|
Integer(10, 25, name='mfi-value'),
|
||||||
|
Integer(15, 45, name='fastd-value'),
|
||||||
|
Integer(20, 50, name='adx-value'),
|
||||||
|
Integer(20, 40, name='rsi-value'),
|
||||||
|
Categorical([True, False], name='mfi-enabled'),
|
||||||
|
Categorical([True, False], name='fastd-enabled'),
|
||||||
|
Categorical([True, False], name='adx-enabled'),
|
||||||
|
Categorical([True, False], name='rsi-enabled'),
|
||||||
|
Categorical(['bb_lower', 'macd_cross_signal', 'sar_reversal'], name='trigger')
|
||||||
|
]
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def sell_strategy_generator(params: Dict[str, Any]) -> Callable:
|
||||||
|
"""
|
||||||
|
Define the sell strategy parameters to be used by Hyperopt.
|
||||||
|
"""
|
||||||
|
def populate_sell_trend(dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||||
|
"""
|
||||||
|
Sell strategy Hyperopt will build and use.
|
||||||
|
"""
|
||||||
|
conditions = []
|
||||||
|
|
||||||
|
# GUARDS AND TRENDS
|
||||||
|
if params.get('sell-mfi-enabled'):
|
||||||
|
conditions.append(dataframe['mfi'] > params['sell-mfi-value'])
|
||||||
|
if params.get('sell-fastd-enabled'):
|
||||||
|
conditions.append(dataframe['fastd'] > params['sell-fastd-value'])
|
||||||
|
if params.get('sell-adx-enabled'):
|
||||||
|
conditions.append(dataframe['adx'] < params['sell-adx-value'])
|
||||||
|
if params.get('sell-rsi-enabled'):
|
||||||
|
conditions.append(dataframe['rsi'] > params['sell-rsi-value'])
|
||||||
|
|
||||||
|
# TRIGGERS
|
||||||
|
if 'sell-trigger' in params:
|
||||||
|
if params['sell-trigger'] == 'sell-bb_upper':
|
||||||
|
conditions.append(dataframe['close'] > dataframe['bb_upperband'])
|
||||||
|
if params['sell-trigger'] == 'sell-macd_cross_signal':
|
||||||
|
conditions.append(qtpylib.crossed_above(
|
||||||
|
dataframe['macdsignal'], dataframe['macd']
|
||||||
|
))
|
||||||
|
if params['sell-trigger'] == 'sell-sar_reversal':
|
||||||
|
conditions.append(qtpylib.crossed_above(
|
||||||
|
dataframe['sar'], dataframe['close']
|
||||||
|
))
|
||||||
|
|
||||||
|
# Check that the candle had volume
|
||||||
|
conditions.append(dataframe['volume'] > 0)
|
||||||
|
|
||||||
|
if conditions:
|
||||||
|
dataframe.loc[
|
||||||
|
reduce(lambda x, y: x & y, conditions),
|
||||||
|
'sell'] = 1
|
||||||
|
|
||||||
|
return dataframe
|
||||||
|
|
||||||
|
return populate_sell_trend
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def sell_indicator_space() -> List[Dimension]:
|
||||||
|
"""
|
||||||
|
Define your Hyperopt space for searching sell strategy parameters.
|
||||||
|
"""
|
||||||
|
return [
|
||||||
|
Integer(75, 100, name='sell-mfi-value'),
|
||||||
|
Integer(50, 100, name='sell-fastd-value'),
|
||||||
|
Integer(50, 100, name='sell-adx-value'),
|
||||||
|
Integer(60, 100, name='sell-rsi-value'),
|
||||||
|
Categorical([True, False], name='sell-mfi-enabled'),
|
||||||
|
Categorical([True, False], name='sell-fastd-enabled'),
|
||||||
|
Categorical([True, False], name='sell-adx-enabled'),
|
||||||
|
Categorical([True, False], name='sell-rsi-enabled'),
|
||||||
|
Categorical(['sell-bb_upper',
|
||||||
|
'sell-macd_cross_signal',
|
||||||
|
'sell-sar_reversal'], name='sell-trigger')
|
||||||
|
]
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def generate_roi_table(params: Dict) -> Dict[int, float]:
|
||||||
|
"""
|
||||||
|
Generate the ROI table that will be used by Hyperopt
|
||||||
|
This implementation generates the default legacy Freqtrade ROI tables.
|
||||||
|
Change it if you need different number of steps in the generated
|
||||||
|
ROI tables or other structure of the ROI tables.
|
||||||
|
Please keep it aligned with parameters in the 'roi' optimization
|
||||||
|
hyperspace defined by the roi_space method.
|
||||||
|
"""
|
||||||
|
roi_table = {}
|
||||||
|
roi_table[0] = params['roi_p1'] + params['roi_p2'] + params['roi_p3']
|
||||||
|
roi_table[params['roi_t3']] = params['roi_p1'] + params['roi_p2']
|
||||||
|
roi_table[params['roi_t3'] + params['roi_t2']] = params['roi_p1']
|
||||||
|
roi_table[params['roi_t3'] + params['roi_t2'] + params['roi_t1']] = 0
|
||||||
|
|
||||||
|
return roi_table
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def roi_space() -> List[Dimension]:
|
||||||
|
"""
|
||||||
|
Values to search for each ROI steps
|
||||||
|
Override it if you need some different ranges for the parameters in the
|
||||||
|
'roi' optimization hyperspace.
|
||||||
|
Please keep it aligned with the implementation of the
|
||||||
|
generate_roi_table method.
|
||||||
|
"""
|
||||||
|
return [
|
||||||
|
Integer(10, 120, name='roi_t1'),
|
||||||
|
Integer(10, 60, name='roi_t2'),
|
||||||
|
Integer(10, 40, name='roi_t3'),
|
||||||
|
Real(0.01, 0.04, name='roi_p1'),
|
||||||
|
Real(0.01, 0.07, name='roi_p2'),
|
||||||
|
Real(0.01, 0.20, name='roi_p3'),
|
||||||
|
]
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def stoploss_space() -> List[Dimension]:
|
||||||
|
"""
|
||||||
|
Stoploss Value to search
|
||||||
|
Override it if you need some different range for the parameter in the
|
||||||
|
'stoploss' optimization hyperspace.
|
||||||
|
"""
|
||||||
|
return [
|
||||||
|
Real(-0.35, -0.02, name='stoploss'),
|
||||||
|
]
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def trailing_space() -> List[Dimension]:
|
||||||
|
"""
|
||||||
|
Create a trailing stoploss space.
|
||||||
|
You may override it in your custom Hyperopt class.
|
||||||
|
"""
|
||||||
|
return [
|
||||||
|
# It was decided to always set trailing_stop is to True if the 'trailing' hyperspace
|
||||||
|
# is used. Otherwise hyperopt will vary other parameters that won't have effect if
|
||||||
|
# trailing_stop is set False.
|
||||||
|
# This parameter is included into the hyperspace dimensions rather than assigning
|
||||||
|
# it explicitly in the code in order to have it printed in the results along with
|
||||||
|
# other 'trailing' hyperspace parameters.
|
||||||
|
Categorical([True], name='trailing_stop'),
|
||||||
|
|
||||||
|
Real(0.01, 0.35, name='trailing_stop_positive'),
|
||||||
|
|
||||||
|
# 'trailing_stop_positive_offset' should be greater than 'trailing_stop_positive',
|
||||||
|
# so this intermediate parameter is used as the value of the difference between
|
||||||
|
# them. The value of the 'trailing_stop_positive_offset' is constructed in the
|
||||||
|
# generate_trailing_params() method.
|
||||||
|
# This is similar to the hyperspace dimensions used for constructing the ROI tables.
|
||||||
|
Real(0.001, 0.1, name='trailing_stop_positive_offset_p1'),
|
||||||
|
|
||||||
|
Categorical([True, False], name='trailing_only_offset_is_reached'),
|
||||||
|
]
|
||||||
|
|
||||||
|
def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||||
|
"""
|
||||||
|
Based on TA indicators.
|
||||||
|
Can be a copy of the corresponding method from the strategy,
|
||||||
|
or will be loaded from the strategy.
|
||||||
|
Must align to populate_indicators used (either from this File, or from the strategy)
|
||||||
|
Only used when --spaces does not include buy
|
||||||
|
"""
|
||||||
|
dataframe.loc[
|
||||||
|
(
|
||||||
|
(dataframe['close'] < dataframe['bb_lowerband']) &
|
||||||
|
(dataframe['mfi'] < 16) &
|
||||||
|
(dataframe['adx'] > 25) &
|
||||||
|
(dataframe['rsi'] < 21)
|
||||||
|
),
|
||||||
|
'buy'] = 1
|
||||||
|
|
||||||
|
return dataframe
|
||||||
|
|
||||||
|
def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||||
|
"""
|
||||||
|
Based on TA indicators.
|
||||||
|
Can be a copy of the corresponding method from the strategy,
|
||||||
|
or will be loaded from the strategy.
|
||||||
|
Must align to populate_indicators used (either from this File, or from the strategy)
|
||||||
|
Only used when --spaces does not include sell
|
||||||
|
"""
|
||||||
|
dataframe.loc[
|
||||||
|
(
|
||||||
|
(qtpylib.crossed_above(
|
||||||
|
dataframe['macdsignal'], dataframe['macd']
|
||||||
|
)) &
|
||||||
|
(dataframe['fastd'] > 54)
|
||||||
|
),
|
||||||
|
'sell'] = 1
|
||||||
|
return dataframe
|
238
user_data/hyperopts/bbrsiopt.py
Normal file
238
user_data/hyperopts/bbrsiopt.py
Normal file
@ -0,0 +1,238 @@
|
|||||||
|
# pragma pylint: disable=missing-docstring, invalid-name, pointless-string-statement
|
||||||
|
|
||||||
|
# --- Do not remove these libs ---
|
||||||
|
from functools import reduce
|
||||||
|
from typing import Any, Callable, Dict, List
|
||||||
|
|
||||||
|
import numpy # noqa
|
||||||
|
import pandas # noqa
|
||||||
|
from pandas import DataFrame
|
||||||
|
from skopt.space import Categorical, Dimension, Integer, Real # noqa
|
||||||
|
|
||||||
|
from freqtrade.optimize.hyperopt_interface import IHyperOpt
|
||||||
|
|
||||||
|
# --------------------------------
|
||||||
|
# Add your lib to import here
|
||||||
|
import talib.abstract as ta # noqa
|
||||||
|
import freqtrade.vendor.qtpylib.indicators as qtpylib
|
||||||
|
|
||||||
|
|
||||||
|
class BBRSIopt(IHyperOpt):
|
||||||
|
@staticmethod
|
||||||
|
def populate_indicators(dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||||
|
|
||||||
|
# RSI
|
||||||
|
dataframe['rsi'] = ta.RSI(dataframe)
|
||||||
|
|
||||||
|
# Bollinger Bands stds 1-4
|
||||||
|
bollinger1 = qtpylib.bollinger_bands(qtpylib.typical_price(dataframe), window=20, stds=1)
|
||||||
|
dataframe['bb_lowerband1'] = bollinger1['lower']
|
||||||
|
dataframe['bb_middleband'] = bollinger1['mid']
|
||||||
|
dataframe['bb_upperband1'] = bollinger1['upper']
|
||||||
|
|
||||||
|
bollinger2 = qtpylib.bollinger_bands(qtpylib.typical_price(dataframe), window=20, stds=2)
|
||||||
|
dataframe['bb_lowerband2'] = bollinger2['lower']
|
||||||
|
dataframe['bb_upperband2'] = bollinger2['upper']
|
||||||
|
|
||||||
|
bollinger3 = qtpylib.bollinger_bands(qtpylib.typical_price(dataframe), window=20, stds=3)
|
||||||
|
dataframe['bb_lowerband3'] = bollinger3['lower']
|
||||||
|
dataframe['bb_upperband3'] = bollinger3['upper']
|
||||||
|
|
||||||
|
bollinger4 = qtpylib.bollinger_bands(qtpylib.typical_price(dataframe), window=20, stds=4)
|
||||||
|
dataframe['bb_lowerband4'] = bollinger4['lower']
|
||||||
|
dataframe['bb_upperband4'] = bollinger4['upper']
|
||||||
|
|
||||||
|
return dataframe
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def buy_strategy_generator(params: Dict[str, Any]) -> Callable:
|
||||||
|
|
||||||
|
def populate_buy_trend(dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||||
|
|
||||||
|
conditions = []
|
||||||
|
|
||||||
|
# GUARDS AND TRENDS
|
||||||
|
if params.get('rsi-enabled'):
|
||||||
|
conditions.append(dataframe['rsi'] > params['rsi-value'])
|
||||||
|
|
||||||
|
# TRIGGERS
|
||||||
|
if 'trigger' in params:
|
||||||
|
if params['trigger'] == 'bb_lower1':
|
||||||
|
conditions.append(dataframe['close'] < dataframe['bb_lowerband1'])
|
||||||
|
if params['trigger'] == 'bb_lower2':
|
||||||
|
conditions.append(dataframe['close'] < dataframe['bb_lowerband2'])
|
||||||
|
if params['trigger'] == 'bb_lower3':
|
||||||
|
conditions.append(dataframe['close'] < dataframe['bb_lowerband3'])
|
||||||
|
if params['trigger'] == 'bb_lower4':
|
||||||
|
conditions.append(dataframe['close'] < dataframe['bb_lowerband4'])
|
||||||
|
|
||||||
|
# Check that the candle had volume
|
||||||
|
conditions.append(dataframe['volume'] > 0)
|
||||||
|
|
||||||
|
if conditions:
|
||||||
|
dataframe.loc[
|
||||||
|
reduce(lambda x, y: x & y, conditions),
|
||||||
|
'buy'] = 1
|
||||||
|
|
||||||
|
return dataframe
|
||||||
|
|
||||||
|
return populate_buy_trend
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def indicator_space() -> List[Dimension]:
|
||||||
|
|
||||||
|
return [
|
||||||
|
Integer(5, 50, name='rsi-value'),
|
||||||
|
Categorical([True, False], name='rsi-enabled'),
|
||||||
|
Categorical(['bb_lower1', 'bb_lower2', 'bb_lower3', 'bb_lower4'], name='trigger')
|
||||||
|
]
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def sell_strategy_generator(params: Dict[str, Any]) -> Callable:
|
||||||
|
|
||||||
|
def populate_sell_trend(dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||||
|
|
||||||
|
conditions = []
|
||||||
|
|
||||||
|
# GUARDS AND TRENDS
|
||||||
|
if params.get('sell-rsi-enabled'):
|
||||||
|
conditions.append(dataframe['rsi'] > params['sell-rsi-value'])
|
||||||
|
|
||||||
|
# TRIGGERS
|
||||||
|
if 'sell-trigger' in params:
|
||||||
|
# All bollinger bands with stds 1-4
|
||||||
|
if params['sell-trigger'] == 'sell-bb_lower3':
|
||||||
|
conditions.append(dataframe['close'] > dataframe['bb_lowerband3'])
|
||||||
|
if params['sell-trigger'] == 'sell-bb_lower2':
|
||||||
|
conditions.append(dataframe['close'] > dataframe['bb_lowerband2'])
|
||||||
|
if params['sell-trigger'] == 'sell-bb_lower1':
|
||||||
|
conditions.append(dataframe['close'] > dataframe['bb_lowerband1'])
|
||||||
|
if params['sell-trigger'] == 'sell-bb_middle':
|
||||||
|
conditions.append(dataframe['close'] > dataframe['bb_middleband'])
|
||||||
|
if params['sell-trigger'] == 'sell-bb_upper1':
|
||||||
|
conditions.append(dataframe['close'] > dataframe['bb_upperband1'])
|
||||||
|
if params['sell-trigger'] == 'sell-bb_upper2':
|
||||||
|
conditions.append(dataframe['close'] > dataframe['bb_upperband2'])
|
||||||
|
if params['sell-trigger'] == 'sell-bb_upper3':
|
||||||
|
conditions.append(dataframe['close'] > dataframe['bb_upperband3'])
|
||||||
|
if params['sell-trigger'] == 'sell-bb_upper4':
|
||||||
|
conditions.append(dataframe['close'] > dataframe['bb_upperband4'])
|
||||||
|
|
||||||
|
# Check that the candle had volume
|
||||||
|
conditions.append(dataframe['volume'] > 0)
|
||||||
|
|
||||||
|
if conditions:
|
||||||
|
dataframe.loc[
|
||||||
|
reduce(lambda x, y: x & y, conditions),
|
||||||
|
'sell'] = 1
|
||||||
|
|
||||||
|
return dataframe
|
||||||
|
|
||||||
|
return populate_sell_trend
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def sell_indicator_space() -> List[Dimension]:
|
||||||
|
|
||||||
|
return [
|
||||||
|
Integer(5, 100, name='sell-rsi-value'),
|
||||||
|
Categorical([True, False], name='sell-rsi-enabled'),
|
||||||
|
Categorical(['sell-bb_lower3',
|
||||||
|
'sell-bb_lower2',
|
||||||
|
'sell-bb_lower1',
|
||||||
|
'sell-bb_middle',
|
||||||
|
'sell-bb_upper1',
|
||||||
|
'sell-bb_upper2',
|
||||||
|
'sell-bb_upper3',
|
||||||
|
'sell-bb_upper4', ], name='sell-trigger')
|
||||||
|
]
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def generate_roi_table(params: Dict) -> Dict[int, float]:
|
||||||
|
# did not touch
|
||||||
|
"""
|
||||||
|
Generate the ROI table that will be used by Hyperopt
|
||||||
|
This implementation generates the default legacy Freqtrade ROI tables.
|
||||||
|
Change it if you need different number of steps in the generated
|
||||||
|
ROI tables or other structure of the ROI tables.
|
||||||
|
Please keep it aligned with parameters in the 'roi' optimization
|
||||||
|
hyperspace defined by the roi_space method.
|
||||||
|
"""
|
||||||
|
roi_table = {}
|
||||||
|
roi_table[0] = params['roi_p1'] + params['roi_p2'] + params['roi_p3']
|
||||||
|
roi_table[params['roi_t3']] = params['roi_p1'] + params['roi_p2']
|
||||||
|
roi_table[params['roi_t3'] + params['roi_t2']] = params['roi_p1']
|
||||||
|
roi_table[params['roi_t3'] + params['roi_t2'] + params['roi_t1']] = 0
|
||||||
|
|
||||||
|
return roi_table
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def roi_space() -> List[Dimension]:
|
||||||
|
# did not touch
|
||||||
|
"""
|
||||||
|
Values to search for each ROI steps
|
||||||
|
Override it if you need some different ranges for the parameters in the
|
||||||
|
'roi' optimization hyperspace.
|
||||||
|
Please keep it aligned with the implementation of the
|
||||||
|
generate_roi_table method.
|
||||||
|
"""
|
||||||
|
return [
|
||||||
|
Integer(10, 120, name='roi_t1'),
|
||||||
|
Integer(10, 60, name='roi_t2'),
|
||||||
|
Integer(10, 40, name='roi_t3'),
|
||||||
|
Real(0.01, 0.04, name='roi_p1'),
|
||||||
|
Real(0.01, 0.07, name='roi_p2'),
|
||||||
|
Real(0.01, 0.20, name='roi_p3'),
|
||||||
|
]
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def stoploss_space() -> List[Dimension]:
|
||||||
|
return [
|
||||||
|
Real(-0.50, -0.02, name='stoploss'),
|
||||||
|
]
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def trailing_space() -> List[Dimension]:
|
||||||
|
# did not touch
|
||||||
|
"""
|
||||||
|
Create a trailing stoploss space.
|
||||||
|
You may override it in your custom Hyperopt class.
|
||||||
|
"""
|
||||||
|
return [
|
||||||
|
# It was decided to always set trailing_stop is to True if the 'trailing' hyperspace
|
||||||
|
# is used. Otherwise hyperopt will vary other parameters that won't have effect if
|
||||||
|
# trailing_stop is set False.
|
||||||
|
# This parameter is included into the hyperspace dimensions rather than assigning
|
||||||
|
# it explicitly in the code in order to have it printed in the results along with
|
||||||
|
# other 'trailing' hyperspace parameters.
|
||||||
|
Categorical([True], name='trailing_stop'),
|
||||||
|
|
||||||
|
Real(0.01, 0.35, name='trailing_stop_positive'),
|
||||||
|
|
||||||
|
# 'trailing_stop_positive_offset' should be greater than 'trailing_stop_positive',
|
||||||
|
# so this intermediate parameter is used as the value of the difference between
|
||||||
|
# them. The value of the 'trailing_stop_positive_offset' is constructed in the
|
||||||
|
# generate_trailing_params() method.
|
||||||
|
# This is similar to the hyperspace dimensions used for constructing the ROI tables.
|
||||||
|
Real(0.001, 0.1, name='trailing_stop_positive_offset_p1'),
|
||||||
|
|
||||||
|
Categorical([True, False], name='trailing_only_offset_is_reached'),
|
||||||
|
]
|
||||||
|
|
||||||
|
def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||||
|
# copy paste from bbrsi.py
|
||||||
|
dataframe.loc[
|
||||||
|
(
|
||||||
|
(dataframe['rsi'] > 30) & # RSI above 30
|
||||||
|
(dataframe['close'] < dataframe['bb_lowerband']) # close price under low bb
|
||||||
|
),
|
||||||
|
'buy'] = 1
|
||||||
|
return dataframe
|
||||||
|
|
||||||
|
def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||||
|
# copy paste from bbrsi.py
|
||||||
|
dataframe.loc[
|
||||||
|
(
|
||||||
|
(dataframe['close'] > dataframe['bb_middleband']) # close price above the middle bb
|
||||||
|
),
|
||||||
|
'sell'] = 1
|
||||||
|
return dataframe
|
247
user_data/hyperopts/examplefreqtrade1opt.py
Normal file
247
user_data/hyperopts/examplefreqtrade1opt.py
Normal file
@ -0,0 +1,247 @@
|
|||||||
|
# pragma pylint: disable=missing-docstring, invalid-name, pointless-string-statement
|
||||||
|
|
||||||
|
# --- Do not remove these libs ---
|
||||||
|
from functools import reduce
|
||||||
|
from typing import Any, Callable, Dict, List
|
||||||
|
|
||||||
|
import numpy # noqa
|
||||||
|
import pandas # noqa
|
||||||
|
from pandas import DataFrame
|
||||||
|
from skopt.space import Categorical, Dimension, Integer, Real # noqa
|
||||||
|
|
||||||
|
from freqtrade.optimize.hyperopt_interface import IHyperOpt
|
||||||
|
|
||||||
|
# --------------------------------
|
||||||
|
# Add your lib to import here
|
||||||
|
import talib.abstract as ta # noqa
|
||||||
|
import freqtrade.vendor.qtpylib.indicators as qtpylib
|
||||||
|
|
||||||
|
|
||||||
|
class Examplestrategy1opt(IHyperOpt):
|
||||||
|
@staticmethod
|
||||||
|
def populate_indicators(dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||||
|
|
||||||
|
dataframe['ema20'] = ta.EMA(dataframe, timeperiod=20)
|
||||||
|
dataframe['ema50'] = ta.EMA(dataframe, timeperiod=50)
|
||||||
|
dataframe['ema100'] = ta.EMA(dataframe, timeperiod=100)
|
||||||
|
|
||||||
|
heikinashi = qtpylib.heikinashi(dataframe)
|
||||||
|
dataframe['ha_open'] = heikinashi['open']
|
||||||
|
dataframe['ha_close'] = heikinashi['close']
|
||||||
|
|
||||||
|
return dataframe
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def buy_strategy_generator(params: Dict[str, Any]) -> Callable:
|
||||||
|
|
||||||
|
def populate_buy_trend(dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||||
|
|
||||||
|
conditions = []
|
||||||
|
|
||||||
|
# GUARDS AND TRENDS
|
||||||
|
if params.get('ema20-enabled'):
|
||||||
|
conditions.append(dataframe['ha_close'] > dataframe['ema20'])
|
||||||
|
if params.get('ema50-enabled'):
|
||||||
|
conditions.append(dataframe['ha_close'] > dataframe['ema50'])
|
||||||
|
if params.get('greenbar-enabled'):
|
||||||
|
conditions.append(dataframe['ha_close'] > dataframe['ha_open'])
|
||||||
|
|
||||||
|
# TRIGGERS
|
||||||
|
if 'trigger' in params:
|
||||||
|
if params['trigger'] == 'ema2050_crossabove':
|
||||||
|
conditions.append(qtpylib.crossed_above(dataframe['ema20'], dataframe['ema50']))
|
||||||
|
if params['trigger'] == 'ema50100_crossabove':
|
||||||
|
conditions.append(qtpylib.crossed_above(
|
||||||
|
dataframe['ema50'], dataframe['ema100']))
|
||||||
|
if params['trigger'] == 'ema20100_crossabove':
|
||||||
|
conditions.append(qtpylib.crossed_above(
|
||||||
|
dataframe['ema20'], dataframe['ema100']))
|
||||||
|
|
||||||
|
# Check that the candle had volume
|
||||||
|
conditions.append(dataframe['volume'] > 0)
|
||||||
|
|
||||||
|
if conditions:
|
||||||
|
dataframe.loc[
|
||||||
|
reduce(lambda x, y: x & y, conditions),
|
||||||
|
'buy'] = 1
|
||||||
|
|
||||||
|
return dataframe
|
||||||
|
|
||||||
|
return populate_buy_trend
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def indicator_space() -> List[Dimension]:
|
||||||
|
"""
|
||||||
|
Define your Hyperopt space for searching buy strategy parameters.
|
||||||
|
"""
|
||||||
|
return [
|
||||||
|
Categorical([True, False], name='ema20-enabled'),
|
||||||
|
Categorical([True, False], name='ema50-enabled'),
|
||||||
|
Categorical([True, False], name='greenbar-enabled'),
|
||||||
|
Categorical(['ema2050_crossabove', 'ema50100_crossabove',
|
||||||
|
'ema20100_crossabove'], name='trigger')
|
||||||
|
]
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def sell_strategy_generator(params: Dict[str, Any]) -> Callable:
|
||||||
|
"""
|
||||||
|
Define the sell strategy parameters to be used by Hyperopt.
|
||||||
|
"""
|
||||||
|
def populate_sell_trend(dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||||
|
"""
|
||||||
|
Sell strategy Hyperopt will build and use.
|
||||||
|
"""
|
||||||
|
conditions = []
|
||||||
|
|
||||||
|
# GUARDS AND TRENDS
|
||||||
|
if params.get('sell-ema20-enabled'):
|
||||||
|
conditions.append(dataframe['ha_close'] < dataframe['ema20'])
|
||||||
|
if params.get('sell-ema50-enabled'):
|
||||||
|
conditions.append(dataframe['ha_close'] < dataframe['ema50'])
|
||||||
|
if params.get('sell-redbar-enabled'):
|
||||||
|
conditions.append(dataframe['ha_close'] < dataframe['ha_open'])
|
||||||
|
|
||||||
|
# TRIGGERS
|
||||||
|
if 'sell-trigger' in params:
|
||||||
|
if params['sell-trigger'] == 'sell-ema2050_crossbelow':
|
||||||
|
conditions.append(qtpylib.crossed_below(dataframe['ema20'], dataframe['ema50']))
|
||||||
|
if params['sell-trigger'] == 'sell-ema50100_crossbelow':
|
||||||
|
conditions.append(qtpylib.crossed_below(
|
||||||
|
dataframe['ema50'], dataframe['ema100']))
|
||||||
|
if params['sell-trigger'] == 'sell-ema20100_crossbelow':
|
||||||
|
conditions.append(qtpylib.crossed_below(
|
||||||
|
dataframe['ema20'], dataframe['ema100']))
|
||||||
|
if params['sell-trigger'] == 'sell-ema50100_crossabove':
|
||||||
|
conditions.append(qtpylib.crossed_above(
|
||||||
|
dataframe['ema50'], dataframe['ema100']))
|
||||||
|
|
||||||
|
# Check that the candle had volume
|
||||||
|
conditions.append(dataframe['volume'] > 0)
|
||||||
|
|
||||||
|
if conditions:
|
||||||
|
dataframe.loc[
|
||||||
|
reduce(lambda x, y: x & y, conditions),
|
||||||
|
'sell'] = 1
|
||||||
|
|
||||||
|
return dataframe
|
||||||
|
|
||||||
|
return populate_sell_trend
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def sell_indicator_space() -> List[Dimension]:
|
||||||
|
|
||||||
|
return [
|
||||||
|
Categorical([True, False], name='sell-ema20-enabled'),
|
||||||
|
Categorical([True, False], name='sell-ema50-enabled'),
|
||||||
|
Categorical([True, False], name='sell-redbar-enabled'),
|
||||||
|
Categorical(['sell-ema2050_crossbelow',
|
||||||
|
'sell-ema50100_crossbelow',
|
||||||
|
'sell-ema20100_crossbelow',
|
||||||
|
'sell-ema50100_crossabove'], name='sell-trigger')
|
||||||
|
]
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def generate_roi_table(params: Dict) -> Dict[int, float]:
|
||||||
|
"""
|
||||||
|
Generate the ROI table that will be used by Hyperopt
|
||||||
|
This implementation generates the default legacy Freqtrade ROI tables.
|
||||||
|
Change it if you need different number of steps in the generated
|
||||||
|
ROI tables or other structure of the ROI tables.
|
||||||
|
Please keep it aligned with parameters in the 'roi' optimization
|
||||||
|
hyperspace defined by the roi_space method.
|
||||||
|
"""
|
||||||
|
roi_table = {}
|
||||||
|
roi_table[0] = params['roi_p1'] + params['roi_p2'] + params['roi_p3']
|
||||||
|
roi_table[params['roi_t3']] = params['roi_p1'] + params['roi_p2']
|
||||||
|
roi_table[params['roi_t3'] + params['roi_t2']] = params['roi_p1']
|
||||||
|
roi_table[params['roi_t3'] + params['roi_t2'] + params['roi_t1']] = 0
|
||||||
|
|
||||||
|
return roi_table
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def roi_space() -> List[Dimension]:
|
||||||
|
"""
|
||||||
|
Values to search for each ROI steps
|
||||||
|
Override it if you need some different ranges for the parameters in the
|
||||||
|
'roi' optimization hyperspace.
|
||||||
|
Please keep it aligned with the implementation of the
|
||||||
|
generate_roi_table method.
|
||||||
|
"""
|
||||||
|
return [
|
||||||
|
Integer(10, 120, name='roi_t1'),
|
||||||
|
Integer(10, 60, name='roi_t2'),
|
||||||
|
Integer(10, 40, name='roi_t3'),
|
||||||
|
Real(0.01, 0.04, name='roi_p1'),
|
||||||
|
Real(0.01, 0.07, name='roi_p2'),
|
||||||
|
Real(0.01, 0.20, name='roi_p3'),
|
||||||
|
]
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def stoploss_space() -> List[Dimension]:
|
||||||
|
"""
|
||||||
|
Stoploss Value to search
|
||||||
|
Override it if you need some different range for the parameter in the
|
||||||
|
'stoploss' optimization hyperspace.
|
||||||
|
"""
|
||||||
|
return [
|
||||||
|
Real(-0.5, -0.02, name='stoploss'),
|
||||||
|
]
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def trailing_space() -> List[Dimension]:
|
||||||
|
"""
|
||||||
|
Create a trailing stoploss space.
|
||||||
|
You may override it in your custom Hyperopt class.
|
||||||
|
"""
|
||||||
|
return [
|
||||||
|
# It was decided to always set trailing_stop is to True if the 'trailing' hyperspace
|
||||||
|
# is used. Otherwise hyperopt will vary other parameters that won't have effect if
|
||||||
|
# trailing_stop is set False.
|
||||||
|
# This parameter is included into the hyperspace dimensions rather than assigning
|
||||||
|
# it explicitly in the code in order to have it printed in the results along with
|
||||||
|
# other 'trailing' hyperspace parameters.
|
||||||
|
Categorical([True], name='trailing_stop'),
|
||||||
|
|
||||||
|
Real(0.01, 0.35, name='trailing_stop_positive'),
|
||||||
|
|
||||||
|
# 'trailing_stop_positive_offset' should be greater than 'trailing_stop_positive',
|
||||||
|
# so this intermediate parameter is used as the value of the difference between
|
||||||
|
# them. The value of the 'trailing_stop_positive_offset' is constructed in the
|
||||||
|
# generate_trailing_params() method.
|
||||||
|
# This is similar to the hyperspace dimensions used for constructing the ROI tables.
|
||||||
|
Real(0.001, 0.1, name='trailing_stop_positive_offset_p1'),
|
||||||
|
|
||||||
|
Categorical([True, False], name='trailing_only_offset_is_reached'),
|
||||||
|
]
|
||||||
|
|
||||||
|
def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||||
|
"""
|
||||||
|
Based on TA indicators, populates the buy signal for the given dataframe
|
||||||
|
:param dataframe: DataFrame
|
||||||
|
:return: DataFrame with buy column
|
||||||
|
"""
|
||||||
|
dataframe.loc[
|
||||||
|
(
|
||||||
|
qtpylib.crossed_above(dataframe['ema20'], dataframe['ema50']) &
|
||||||
|
(dataframe['ha_close'] > dataframe['ema20']) &
|
||||||
|
(dataframe['ha_open'] < dataframe['ha_close']) # green bar
|
||||||
|
),
|
||||||
|
'buy'] = 1
|
||||||
|
|
||||||
|
return dataframe
|
||||||
|
|
||||||
|
def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||||
|
"""
|
||||||
|
Based on TA indicators, populates the sell signal for the given dataframe
|
||||||
|
:param dataframe: DataFrame
|
||||||
|
:return: DataFrame with buy column
|
||||||
|
"""
|
||||||
|
dataframe.loc[
|
||||||
|
(
|
||||||
|
qtpylib.crossed_above(dataframe['ema50'], dataframe['ema100']) &
|
||||||
|
(dataframe['ha_close'] < dataframe['ema20']) &
|
||||||
|
(dataframe['ha_open'] > dataframe['ha_close']) # red bar
|
||||||
|
),
|
||||||
|
'sell'] = 1
|
||||||
|
|
||||||
|
return dataframe
|
281
user_data/hyperopts/examplefreqtrade2opt.py
Normal file
281
user_data/hyperopts/examplefreqtrade2opt.py
Normal file
@ -0,0 +1,281 @@
|
|||||||
|
# pragma pylint: disable=missing-docstring, invalid-name, pointless-string-statement
|
||||||
|
|
||||||
|
# --- Do not remove these libs ---
|
||||||
|
from functools import reduce
|
||||||
|
from typing import Any, Callable, Dict, List
|
||||||
|
|
||||||
|
import numpy # noqa
|
||||||
|
import pandas # noqa
|
||||||
|
from pandas import DataFrame
|
||||||
|
from skopt.space import Categorical, Dimension, Integer, Real # noqa
|
||||||
|
|
||||||
|
from freqtrade.optimize.hyperopt_interface import IHyperOpt
|
||||||
|
|
||||||
|
# --------------------------------
|
||||||
|
# Add your lib to import here
|
||||||
|
import talib.abstract as ta # noqa
|
||||||
|
import freqtrade.vendor.qtpylib.indicators as qtpylib
|
||||||
|
|
||||||
|
|
||||||
|
class Examplestrategy2opt(IHyperOpt):
|
||||||
|
@staticmethod
|
||||||
|
def populate_indicators(dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||||
|
|
||||||
|
# Stoch
|
||||||
|
stoch = ta.STOCH(dataframe)
|
||||||
|
dataframe['slowk'] = stoch['slowk']
|
||||||
|
|
||||||
|
# RSI
|
||||||
|
dataframe['rsi'] = ta.RSI(dataframe)
|
||||||
|
|
||||||
|
# Inverse Fisher transform on RSI, values [-1.0, 1.0] (https://goo.gl/2JGGoy)
|
||||||
|
rsi = 0.1 * (dataframe['rsi'] - 50)
|
||||||
|
dataframe['fisher_rsi'] = (numpy.exp(2 * rsi) - 1) / (numpy.exp(2 * rsi) + 1)
|
||||||
|
|
||||||
|
# Bollinger bands
|
||||||
|
bollinger1 = qtpylib.bollinger_bands(qtpylib.typical_price(dataframe), window=20, stds=1)
|
||||||
|
dataframe['bb_lowerband1'] = bollinger1['lower']
|
||||||
|
dataframe['bb_middleband'] = bollinger1['mid']
|
||||||
|
dataframe['bb_upperband1'] = bollinger1['upper']
|
||||||
|
|
||||||
|
bollinger2 = qtpylib.bollinger_bands(qtpylib.typical_price(dataframe), window=20, stds=2)
|
||||||
|
dataframe['bb_lowerband2'] = bollinger2['lower']
|
||||||
|
dataframe['bb_upperband2'] = bollinger2['upper']
|
||||||
|
|
||||||
|
bollinger3 = qtpylib.bollinger_bands(qtpylib.typical_price(dataframe), window=20, stds=3)
|
||||||
|
dataframe['bb_lowerband3'] = bollinger3['lower']
|
||||||
|
dataframe['bb_upperband3'] = bollinger3['upper']
|
||||||
|
|
||||||
|
bollinger4 = qtpylib.bollinger_bands(qtpylib.typical_price(dataframe), window=20, stds=4)
|
||||||
|
dataframe['bb_lowerband4'] = bollinger4['lower']
|
||||||
|
dataframe['bb_upperband4'] = bollinger4['upper']
|
||||||
|
|
||||||
|
# SAR Parabol
|
||||||
|
dataframe['sar'] = ta.SAR(dataframe)
|
||||||
|
|
||||||
|
# Hammer: values [0, 100]
|
||||||
|
dataframe['CDLHAMMER'] = ta.CDLHAMMER(dataframe)
|
||||||
|
|
||||||
|
return dataframe
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def buy_strategy_generator(params: Dict[str, Any]) -> Callable:
|
||||||
|
"""
|
||||||
|
Define the buy strategy parameters to be used by Hyperopt.
|
||||||
|
"""
|
||||||
|
def populate_buy_trend(dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||||
|
"""
|
||||||
|
Buy strategy Hyperopt will build and use.
|
||||||
|
"""
|
||||||
|
conditions = []
|
||||||
|
|
||||||
|
# GUARDS AND TRENDS
|
||||||
|
if params.get('rsi-enabled'):
|
||||||
|
conditions.append(dataframe['rsi'] < params['rsi-value'])
|
||||||
|
|
||||||
|
if params.get('slowk-enabled'):
|
||||||
|
conditions.append(dataframe['slowk'] < params['slowk-value'])
|
||||||
|
|
||||||
|
if params.get('Hammer-enabled'):
|
||||||
|
conditions.append(dataframe['CDLHAMMER'] < params['Hammer-value'])
|
||||||
|
|
||||||
|
# TRIGGERS
|
||||||
|
if 'trigger' in params:
|
||||||
|
if params['trigger'] == 'bb_lower1':
|
||||||
|
conditions.append(dataframe['close'] < dataframe['bb_lowerband1'])
|
||||||
|
if params['trigger'] == 'bb_lower2':
|
||||||
|
conditions.append(dataframe['close'] < dataframe['bb_lowerband2'])
|
||||||
|
if params['trigger'] == 'bb_lower3':
|
||||||
|
conditions.append(dataframe['close'] < dataframe['bb_lowerband3'])
|
||||||
|
if params['trigger'] == 'bb_lower4':
|
||||||
|
conditions.append(dataframe['close'] < dataframe['bb_lowerband4'])
|
||||||
|
|
||||||
|
# Check that the candle had volume
|
||||||
|
conditions.append(dataframe['volume'] > 0)
|
||||||
|
|
||||||
|
if conditions:
|
||||||
|
dataframe.loc[
|
||||||
|
reduce(lambda x, y: x & y, conditions),
|
||||||
|
'buy'] = 1
|
||||||
|
|
||||||
|
return dataframe
|
||||||
|
|
||||||
|
return populate_buy_trend
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def indicator_space() -> List[Dimension]:
|
||||||
|
"""
|
||||||
|
Define your Hyperopt space for searching buy strategy parameters.
|
||||||
|
"""
|
||||||
|
return [
|
||||||
|
Integer(0, 100, name='slowk-value'),
|
||||||
|
Integer(20, 80, name='rsi-value'),
|
||||||
|
Integer(0, 100, name='Hammer-value'),
|
||||||
|
Categorical([True, False], name='slowk-enabled'),
|
||||||
|
Categorical([True, False], name='rsi-enabled'),
|
||||||
|
Categorical([True, False], name='Hammer-enabled'),
|
||||||
|
Categorical(['bb_lower1', 'bb_lower2', 'bb_lower3', 'bb_lower4'], name='trigger')
|
||||||
|
]
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def sell_strategy_generator(params: Dict[str, Any]) -> Callable:
|
||||||
|
"""
|
||||||
|
Define the sell strategy parameters to be used by Hyperopt.
|
||||||
|
"""
|
||||||
|
def populate_sell_trend(dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||||
|
"""
|
||||||
|
Sell strategy Hyperopt will build and use.
|
||||||
|
"""
|
||||||
|
conditions = []
|
||||||
|
|
||||||
|
# GUARDS AND TRENDS
|
||||||
|
if params.get('sell-fisher-enabled'):
|
||||||
|
conditions.append(dataframe['fisher_rsi'] > params['sell-fisher-value'])
|
||||||
|
|
||||||
|
# TRIGGERS
|
||||||
|
if 'sell-trigger' in params:
|
||||||
|
if params['sell-trigger'] == 'sell-bb_middle':
|
||||||
|
conditions.append(dataframe['close'] > dataframe['bb_middleband'])
|
||||||
|
if params['sell-trigger'] == 'sell-bb_upper1':
|
||||||
|
conditions.append(dataframe['close'] > dataframe['bb_upperband1'])
|
||||||
|
if params['sell-trigger'] == 'sell-bb_upper2':
|
||||||
|
conditions.append(dataframe['close'] > dataframe['bb_upperband2'])
|
||||||
|
if params['sell-trigger'] == 'sell-bb_upper3':
|
||||||
|
conditions.append(dataframe['close'] > dataframe['bb_upperband3'])
|
||||||
|
if params['sell-trigger'] == 'sell-bb_upper4':
|
||||||
|
conditions.append(dataframe['close'] > dataframe['bb_upperband4'])
|
||||||
|
if params['sell-trigger'] == 'sell-sar':
|
||||||
|
conditions.append(dataframe['close'] < dataframe['sar'])
|
||||||
|
|
||||||
|
# Check that the candle had volume
|
||||||
|
conditions.append(dataframe['volume'] > 0)
|
||||||
|
|
||||||
|
if conditions:
|
||||||
|
dataframe.loc[
|
||||||
|
reduce(lambda x, y: x & y, conditions),
|
||||||
|
'sell'] = 1
|
||||||
|
|
||||||
|
return dataframe
|
||||||
|
|
||||||
|
return populate_sell_trend
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def sell_indicator_space() -> List[Dimension]:
|
||||||
|
"""
|
||||||
|
Define your Hyperopt space for searching sell strategy parameters.
|
||||||
|
"""
|
||||||
|
return [
|
||||||
|
Integer(-1.0, 1.0, name='sell-fisher-value'),
|
||||||
|
Categorical([True, False], name='sell-fisher-enabled'),
|
||||||
|
Categorical(['sell-sar'
|
||||||
|
'sell-bb_middle',
|
||||||
|
'sell-bb_upper1',
|
||||||
|
'sell-bb_upper2',
|
||||||
|
'sell-bb_upper3',
|
||||||
|
'sell-bb_upper4', ], name='sell-trigger')
|
||||||
|
]
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def generate_roi_table(params: Dict) -> Dict[int, float]:
|
||||||
|
"""
|
||||||
|
Generate the ROI table that will be used by Hyperopt
|
||||||
|
This implementation generates the default legacy Freqtrade ROI tables.
|
||||||
|
Change it if you need different number of steps in the generated
|
||||||
|
ROI tables or other structure of the ROI tables.
|
||||||
|
Please keep it aligned with parameters in the 'roi' optimization
|
||||||
|
hyperspace defined by the roi_space method.
|
||||||
|
"""
|
||||||
|
roi_table = {}
|
||||||
|
roi_table[0] = params['roi_p1'] + params['roi_p2'] + params['roi_p3']
|
||||||
|
roi_table[params['roi_t3']] = params['roi_p1'] + params['roi_p2']
|
||||||
|
roi_table[params['roi_t3'] + params['roi_t2']] = params['roi_p1']
|
||||||
|
roi_table[params['roi_t3'] + params['roi_t2'] + params['roi_t1']] = 0
|
||||||
|
|
||||||
|
return roi_table
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def roi_space() -> List[Dimension]:
|
||||||
|
"""
|
||||||
|
Values to search for each ROI steps
|
||||||
|
Override it if you need some different ranges for the parameters in the
|
||||||
|
'roi' optimization hyperspace.
|
||||||
|
Please keep it aligned with the implementation of the
|
||||||
|
generate_roi_table method.
|
||||||
|
"""
|
||||||
|
return [
|
||||||
|
Integer(10, 120, name='roi_t1'),
|
||||||
|
Integer(10, 60, name='roi_t2'),
|
||||||
|
Integer(10, 40, name='roi_t3'),
|
||||||
|
Real(0.01, 0.04, name='roi_p1'),
|
||||||
|
Real(0.01, 0.07, name='roi_p2'),
|
||||||
|
Real(0.01, 0.20, name='roi_p3'),
|
||||||
|
]
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def stoploss_space() -> List[Dimension]:
|
||||||
|
"""
|
||||||
|
Stoploss Value to search
|
||||||
|
Override it if you need some different range for the parameter in the
|
||||||
|
'stoploss' optimization hyperspace.
|
||||||
|
"""
|
||||||
|
return [
|
||||||
|
Real(-0.35, -0.02, name='stoploss'),
|
||||||
|
]
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def trailing_space() -> List[Dimension]:
|
||||||
|
"""
|
||||||
|
Create a trailing stoploss space.
|
||||||
|
You may override it in your custom Hyperopt class.
|
||||||
|
"""
|
||||||
|
return [
|
||||||
|
# It was decided to always set trailing_stop is to True if the 'trailing' hyperspace
|
||||||
|
# is used. Otherwise hyperopt will vary other parameters that won't have effect if
|
||||||
|
# trailing_stop is set False.
|
||||||
|
# This parameter is included into the hyperspace dimensions rather than assigning
|
||||||
|
# it explicitly in the code in order to have it printed in the results along with
|
||||||
|
# other 'trailing' hyperspace parameters.
|
||||||
|
Categorical([True], name='trailing_stop'),
|
||||||
|
|
||||||
|
Real(0.01, 0.35, name='trailing_stop_positive'),
|
||||||
|
|
||||||
|
# 'trailing_stop_positive_offset' should be greater than 'trailing_stop_positive',
|
||||||
|
# so this intermediate parameter is used as the value of the difference between
|
||||||
|
# them. The value of the 'trailing_stop_positive_offset' is constructed in the
|
||||||
|
# generate_trailing_params() method.
|
||||||
|
# This is similar to the hyperspace dimensions used for constructing the ROI tables.
|
||||||
|
Real(0.001, 0.1, name='trailing_stop_positive_offset_p1'),
|
||||||
|
|
||||||
|
Categorical([True, False], name='trailing_only_offset_is_reached'),
|
||||||
|
]
|
||||||
|
|
||||||
|
def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||||
|
"""
|
||||||
|
Based on TA indicators, populates the buy signal for the given dataframe
|
||||||
|
:param dataframe: DataFrame
|
||||||
|
:return: DataFrame with buy column
|
||||||
|
"""
|
||||||
|
dataframe.loc[
|
||||||
|
(
|
||||||
|
(dataframe['rsi'] < 30) &
|
||||||
|
(dataframe['slowk'] < 20) &
|
||||||
|
(dataframe['bb_lowerband'] > dataframe['close']) &
|
||||||
|
(dataframe['CDLHAMMER'] == 100)
|
||||||
|
),
|
||||||
|
'buy'] = 1
|
||||||
|
|
||||||
|
return dataframe
|
||||||
|
|
||||||
|
def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||||
|
"""
|
||||||
|
Based on TA indicators, populates the sell signal for the given dataframe
|
||||||
|
:param dataframe: DataFrame
|
||||||
|
:return: DataFrame with buy column
|
||||||
|
"""
|
||||||
|
dataframe.loc[
|
||||||
|
(
|
||||||
|
(dataframe['sar'] > dataframe['close']) &
|
||||||
|
(dataframe['fisher_rsi'] > 0.3)
|
||||||
|
),
|
||||||
|
'sell'] = 1
|
||||||
|
return dataframe
|
275
user_data/hyperopts/examplefreqtrade3opt.py
Normal file
275
user_data/hyperopts/examplefreqtrade3opt.py
Normal file
@ -0,0 +1,275 @@
|
|||||||
|
# pragma pylint: disable=missing-docstring, invalid-name, pointless-string-statement
|
||||||
|
|
||||||
|
# --- Do not remove these libs ---
|
||||||
|
from functools import reduce
|
||||||
|
from typing import Any, Callable, Dict, List
|
||||||
|
|
||||||
|
import numpy # noqa
|
||||||
|
import pandas # noqa
|
||||||
|
from pandas import DataFrame
|
||||||
|
from skopt.space import Categorical, Dimension, Integer, Real # noqa
|
||||||
|
|
||||||
|
from freqtrade.optimize.hyperopt_interface import IHyperOpt
|
||||||
|
|
||||||
|
# --------------------------------
|
||||||
|
# Add your lib to import here
|
||||||
|
import talib.abstract as ta # noqa
|
||||||
|
import freqtrade.vendor.qtpylib.indicators as qtpylib
|
||||||
|
|
||||||
|
|
||||||
|
class Examplestrategy3opt(IHyperOpt):
|
||||||
|
@staticmethod
|
||||||
|
def populate_indicators(dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||||
|
|
||||||
|
# MFI
|
||||||
|
dataframe['mfi'] = ta.MFI(dataframe)
|
||||||
|
|
||||||
|
# Stoch fast
|
||||||
|
stoch_fast = ta.STOCHF(dataframe)
|
||||||
|
dataframe['fastd'] = stoch_fast['fastd']
|
||||||
|
dataframe['fastk'] = stoch_fast['fastk']
|
||||||
|
|
||||||
|
# RSI
|
||||||
|
dataframe['rsi'] = ta.RSI(dataframe)
|
||||||
|
|
||||||
|
# Inverse Fisher transform on RSI, values [-1.0, 1.0] (https://goo.gl/2JGGoy)
|
||||||
|
rsi = 0.1 * (dataframe['rsi'] - 50)
|
||||||
|
dataframe['fisher_rsi'] = (numpy.exp(2 * rsi) - 1) / (numpy.exp(2 * rsi) + 1)
|
||||||
|
|
||||||
|
# Bollinger bands
|
||||||
|
bollinger = qtpylib.bollinger_bands(qtpylib.typical_price(dataframe), window=20, stds=2)
|
||||||
|
dataframe['bb_lowerband'] = bollinger['lower']
|
||||||
|
|
||||||
|
# EMA - Exponential Moving Average
|
||||||
|
dataframe['ema5'] = ta.EMA(dataframe, timeperiod=5)
|
||||||
|
dataframe['ema10'] = ta.EMA(dataframe, timeperiod=10)
|
||||||
|
dataframe['ema50'] = ta.EMA(dataframe, timeperiod=50)
|
||||||
|
dataframe['ema100'] = ta.EMA(dataframe, timeperiod=100)
|
||||||
|
|
||||||
|
# SAR Parabol
|
||||||
|
dataframe['sar'] = ta.SAR(dataframe)
|
||||||
|
|
||||||
|
# SMA - Simple Moving Average
|
||||||
|
dataframe['sma'] = ta.SMA(dataframe, timeperiod=40)
|
||||||
|
|
||||||
|
return dataframe
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def buy_strategy_generator(params: Dict[str, Any]) -> Callable:
|
||||||
|
"""
|
||||||
|
Define the buy strategy parameters to be used by Hyperopt.
|
||||||
|
"""
|
||||||
|
def populate_buy_trend(dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||||
|
"""
|
||||||
|
Buy strategy Hyperopt will build and use.
|
||||||
|
"""
|
||||||
|
conditions = []
|
||||||
|
|
||||||
|
# GUARDS AND TRENDS
|
||||||
|
if params.get('mfi-enabled'):
|
||||||
|
conditions.append(dataframe['mfi'] < params['mfi-value'])
|
||||||
|
if params.get('fastd-enabled'):
|
||||||
|
conditions.append(dataframe['fastd'] > params['fastd-value'])
|
||||||
|
if params.get('rsi_min-enabled'):
|
||||||
|
conditions.append(dataframe['rsi'] > params['rsi_min-value'])
|
||||||
|
if params.get('rsi_max-enabled'):
|
||||||
|
conditions.append(dataframe['rsi'] < params['rsi_max-value'])
|
||||||
|
if params.get('fisher_max-enabled'):
|
||||||
|
conditions.append(dataframe['fisher_rsi'] < params['fisher_rsi_max-value'])
|
||||||
|
if params.get('fisher_min-enabled'):
|
||||||
|
conditions.append(dataframe['fisher_rsi'] > params['fisher_rsi_min-value'])
|
||||||
|
|
||||||
|
# TRIGGERS
|
||||||
|
if 'trigger' in params:
|
||||||
|
if params['trigger'] == 'fastk':
|
||||||
|
conditions.append(dataframe['fastd'] > dataframe['fastk'])
|
||||||
|
if params['trigger'] == 'sma_reversal':
|
||||||
|
conditions.append(dataframe['close'] < dataframe['sma'])
|
||||||
|
if params['trigger'] == 'ema':
|
||||||
|
conditions.append((dataframe['ema50'] > dataframe['ema100']) |
|
||||||
|
(qtpylib.crossed_above(dataframe['ema5'], dataframe['ema10'])))
|
||||||
|
|
||||||
|
# Check that the candle had volume
|
||||||
|
conditions.append(dataframe['volume'] > 0)
|
||||||
|
|
||||||
|
if conditions:
|
||||||
|
dataframe.loc[
|
||||||
|
reduce(lambda x, y: x & y, conditions),
|
||||||
|
'buy']=1
|
||||||
|
|
||||||
|
return dataframe
|
||||||
|
|
||||||
|
return populate_buy_trend
|
||||||
|
|
||||||
|
@ staticmethod
|
||||||
|
def indicator_space() -> List[Dimension]:
|
||||||
|
"""
|
||||||
|
Define your Hyperopt space for searching buy strategy parameters.
|
||||||
|
"""
|
||||||
|
return [
|
||||||
|
Integer(5, 40, name='mfi-value'),
|
||||||
|
Integer(0, 50, name='fastd-value'),
|
||||||
|
Integer(0, 15, name='rsi_min-value'),
|
||||||
|
Integer(10, 50, name='rsi_max-value'),
|
||||||
|
Integer(-1, 0.5, name='fisher_rsi_min-value'),
|
||||||
|
Integer(-0.5, 1, name='fisher_rsi_max-value'),
|
||||||
|
Categorical([True, False], name='mfi-enabled'),
|
||||||
|
Categorical([True, False], name='fastd-enabled'),
|
||||||
|
Categorical([True, False], name='rsi_min-enabled'),
|
||||||
|
Categorical([True, False], name='rsi_max-enabled'),
|
||||||
|
Categorical([True, False], name='fisher_min-enabled'),
|
||||||
|
Categorical([True, False], name='fisher_max-enabled'),
|
||||||
|
Categorical(['fastk', 'sma_reversal', 'ema'], name='trigger')
|
||||||
|
]
|
||||||
|
|
||||||
|
@ staticmethod
|
||||||
|
def sell_strategy_generator(params: Dict[str, Any]) -> Callable:
|
||||||
|
"""
|
||||||
|
Define the sell strategy parameters to be used by Hyperopt.
|
||||||
|
"""
|
||||||
|
def populate_sell_trend(dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||||
|
"""
|
||||||
|
Sell strategy Hyperopt will build and use.
|
||||||
|
"""
|
||||||
|
conditions = []
|
||||||
|
|
||||||
|
# GUARDS AND TRENDS
|
||||||
|
if params.get('sell-fisher-enabled'):
|
||||||
|
conditions.append(dataframe['fisher_rsi'] > params['sell-fisher-value'])
|
||||||
|
|
||||||
|
# TRIGGERS
|
||||||
|
if 'sell-trigger' in params:
|
||||||
|
if params['sell-trigger'] == 'sell-sar':
|
||||||
|
conditions.append(dataframe['sar'] > dataframe['close'])
|
||||||
|
|
||||||
|
# Check that the candle had volume
|
||||||
|
conditions.append(dataframe['volume'] > 0)
|
||||||
|
|
||||||
|
if conditions:
|
||||||
|
dataframe.loc[
|
||||||
|
reduce(lambda x, y: x & y, conditions),
|
||||||
|
'sell']=1
|
||||||
|
|
||||||
|
return dataframe
|
||||||
|
|
||||||
|
return populate_sell_trend
|
||||||
|
|
||||||
|
@ staticmethod
|
||||||
|
def sell_indicator_space() -> List[Dimension]:
|
||||||
|
"""
|
||||||
|
Define your Hyperopt space for searching sell strategy parameters.
|
||||||
|
"""
|
||||||
|
return [
|
||||||
|
Integer(-1, 1, name='sell-fisher-value'),
|
||||||
|
Categorical([True, False], name='sell-fisher-enabled'),
|
||||||
|
Categorical(['sell-sar'], name='sell-trigger')
|
||||||
|
]
|
||||||
|
|
||||||
|
@ staticmethod
|
||||||
|
def generate_roi_table(params: Dict) -> Dict[int, float]:
|
||||||
|
"""
|
||||||
|
Generate the ROI table that will be used by Hyperopt
|
||||||
|
This implementation generates the default legacy Freqtrade ROI tables.
|
||||||
|
Change it if you need different number of steps in the generated
|
||||||
|
ROI tables or other structure of the ROI tables.
|
||||||
|
Please keep it aligned with parameters in the 'roi' optimization
|
||||||
|
hyperspace defined by the roi_space method.
|
||||||
|
"""
|
||||||
|
roi_table = {}
|
||||||
|
roi_table[0] = params['roi_p1'] + params['roi_p2'] + params['roi_p3']
|
||||||
|
roi_table[params['roi_t3']] = params['roi_p1'] + params['roi_p2']
|
||||||
|
roi_table[params['roi_t3'] + params['roi_t2']] = params['roi_p1']
|
||||||
|
roi_table[params['roi_t3'] + params['roi_t2'] + params['roi_t1']] = 0
|
||||||
|
|
||||||
|
return roi_table
|
||||||
|
|
||||||
|
@ staticmethod
|
||||||
|
def roi_space() -> List[Dimension]:
|
||||||
|
"""
|
||||||
|
Values to search for each ROI steps
|
||||||
|
Override it if you need some different ranges for the parameters in the
|
||||||
|
'roi' optimization hyperspace.
|
||||||
|
Please keep it aligned with the implementation of the
|
||||||
|
generate_roi_table method.
|
||||||
|
"""
|
||||||
|
return [
|
||||||
|
Integer(10, 120, name='roi_t1'),
|
||||||
|
Integer(10, 60, name='roi_t2'),
|
||||||
|
Integer(10, 40, name='roi_t3'),
|
||||||
|
Real(0.01, 0.04, name='roi_p1'),
|
||||||
|
Real(0.01, 0.07, name='roi_p2'),
|
||||||
|
Real(0.01, 0.20, name='roi_p3'),
|
||||||
|
]
|
||||||
|
|
||||||
|
@ staticmethod
|
||||||
|
def stoploss_space() -> List[Dimension]:
|
||||||
|
"""
|
||||||
|
Stoploss Value to search
|
||||||
|
Override it if you need some different range for the parameter in the
|
||||||
|
'stoploss' optimization hyperspace.
|
||||||
|
"""
|
||||||
|
return [
|
||||||
|
Real(-0.35, -0.02, name='stoploss'),
|
||||||
|
]
|
||||||
|
|
||||||
|
@ staticmethod
|
||||||
|
def trailing_space() -> List[Dimension]:
|
||||||
|
"""
|
||||||
|
Create a trailing stoploss space.
|
||||||
|
You may override it in your custom Hyperopt class.
|
||||||
|
"""
|
||||||
|
return [
|
||||||
|
# It was decided to always set trailing_stop is to True if the 'trailing' hyperspace
|
||||||
|
# is used. Otherwise hyperopt will vary other parameters that won't have effect if
|
||||||
|
# trailing_stop is set False.
|
||||||
|
# This parameter is included into the hyperspace dimensions rather than assigning
|
||||||
|
# it explicitly in the code in order to have it printed in the results along with
|
||||||
|
# other 'trailing' hyperspace parameters.
|
||||||
|
Categorical([True], name='trailing_stop'),
|
||||||
|
|
||||||
|
Real(0.01, 0.35, name='trailing_stop_positive'),
|
||||||
|
|
||||||
|
# 'trailing_stop_positive_offset' should be greater than 'trailing_stop_positive',
|
||||||
|
# so this intermediate parameter is used as the value of the difference between
|
||||||
|
# them. The value of the 'trailing_stop_positive_offset' is constructed in the
|
||||||
|
# generate_trailing_params() method.
|
||||||
|
# This is similar to the hyperspace dimensions used for constructing the ROI tables.
|
||||||
|
Real(0.001, 0.1, name='trailing_stop_positive_offset_p1'),
|
||||||
|
|
||||||
|
Categorical([True, False], name='trailing_only_offset_is_reached'),
|
||||||
|
]
|
||||||
|
|
||||||
|
def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||||
|
dataframe.loc[
|
||||||
|
(
|
||||||
|
(dataframe['rsi'] < 28) &
|
||||||
|
(dataframe['rsi'] > 0) &
|
||||||
|
(dataframe['close'] < dataframe['sma']) &
|
||||||
|
(dataframe['fisher_rsi'] < -0.94) &
|
||||||
|
(dataframe['mfi'] < 16.0) &
|
||||||
|
(
|
||||||
|
(dataframe['ema50'] > dataframe['ema100']) |
|
||||||
|
(qtpylib.crossed_above(dataframe['ema5'], dataframe['ema10']))
|
||||||
|
) &
|
||||||
|
(dataframe['fastd'] > dataframe['fastk']) &
|
||||||
|
(dataframe['fastd'] > 0)
|
||||||
|
),
|
||||||
|
'buy'] = 1
|
||||||
|
|
||||||
|
return dataframe
|
||||||
|
|
||||||
|
def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||||
|
"""
|
||||||
|
Based on TA indicators.
|
||||||
|
Can be a copy of the corresponding method from the strategy,
|
||||||
|
or will be loaded from the strategy.
|
||||||
|
Must align to populate_indicators used (either from this File, or from the strategy)
|
||||||
|
Only used when --spaces does not include sell
|
||||||
|
"""
|
||||||
|
dataframe.loc[
|
||||||
|
(
|
||||||
|
(dataframe['sar'] > dataframe['close']) &
|
||||||
|
(dataframe['fisher_rsi'] > 0.3)
|
||||||
|
),
|
||||||
|
'sell'] = 1
|
||||||
|
return dataframe
|
304
user_data/hyperopts/examplefreqtrade4opt.py
Normal file
304
user_data/hyperopts/examplefreqtrade4opt.py
Normal file
@ -0,0 +1,304 @@
|
|||||||
|
# pragma pylint: disable=missing-docstring, invalid-name, pointless-string-statement
|
||||||
|
|
||||||
|
# --- Do not remove these libs ---
|
||||||
|
from functools import reduce
|
||||||
|
from typing import Any, Callable, Dict, List
|
||||||
|
|
||||||
|
import numpy # noqa
|
||||||
|
import pandas # noqa
|
||||||
|
from pandas import DataFrame
|
||||||
|
from skopt.space import Categorical, Dimension, Integer, Real # noqa
|
||||||
|
|
||||||
|
from freqtrade.optimize.hyperopt_interface import IHyperOpt
|
||||||
|
|
||||||
|
# --------------------------------
|
||||||
|
# Add your lib to import here
|
||||||
|
import talib.abstract as ta # noqa
|
||||||
|
import freqtrade.vendor.qtpylib.indicators as qtpylib
|
||||||
|
|
||||||
|
|
||||||
|
class Examplestrategy4opt(IHyperOpt):
|
||||||
|
@staticmethod
|
||||||
|
def populate_indicators(dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||||
|
|
||||||
|
# ADX
|
||||||
|
dataframe['adx'] = ta.ADX(dataframe)
|
||||||
|
dataframe['slowadx'] = ta.ADX(dataframe, 35)
|
||||||
|
|
||||||
|
# Commodity Channel Index: values Oversold:<-100, Overbought:>100
|
||||||
|
dataframe['cci'] = ta.CCI(dataframe)
|
||||||
|
|
||||||
|
# Stoch
|
||||||
|
stoch = ta.STOCHF(dataframe, 5)
|
||||||
|
dataframe['fastd'] = stoch['fastd']
|
||||||
|
dataframe['fastk'] = stoch['fastk']
|
||||||
|
dataframe['fastk-previous'] = dataframe.fastk.shift(1)
|
||||||
|
dataframe['fastd-previous'] = dataframe.fastd.shift(1)
|
||||||
|
|
||||||
|
# Slow Stoch
|
||||||
|
slowstoch = ta.STOCHF(dataframe, 50)
|
||||||
|
dataframe['slowfastd'] = slowstoch['fastd']
|
||||||
|
dataframe['slowfastk'] = slowstoch['fastk']
|
||||||
|
dataframe['slowfastk-previous'] = dataframe.slowfastk.shift(1)
|
||||||
|
dataframe['slowfastd-previous'] = dataframe.slowfastd.shift(1)
|
||||||
|
|
||||||
|
# EMA - Exponential Moving Average
|
||||||
|
dataframe['ema5'] = ta.EMA(dataframe, timeperiod=5)
|
||||||
|
|
||||||
|
dataframe['mean-volume'] = dataframe['volume'].mean()
|
||||||
|
|
||||||
|
return dataframe
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def buy_strategy_generator(params: Dict[str, Any]) -> Callable:
|
||||||
|
"""
|
||||||
|
Define the buy strategy parameters to be used by Hyperopt.
|
||||||
|
"""
|
||||||
|
def populate_buy_trend(dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||||
|
"""
|
||||||
|
Buy strategy Hyperopt will build and use.
|
||||||
|
"""
|
||||||
|
conditions = []
|
||||||
|
|
||||||
|
# GUARDS AND TRENDS
|
||||||
|
if params.get('adx-enabled'):
|
||||||
|
conditions.append(
|
||||||
|
(dataframe['adx'] > params['adx-value']) |
|
||||||
|
(dataframe['slowadx'] > params['slowadx-value'])
|
||||||
|
)
|
||||||
|
|
||||||
|
if params.get('cci-enabled'):
|
||||||
|
conditions.append(dataframe['cci'] < params['cci-value'])
|
||||||
|
|
||||||
|
if params.get('fastk-previous-enabled'):
|
||||||
|
conditions.append(dataframe['fastk-previous'] < params['fastk-previous-value'])
|
||||||
|
if params.get('fastd-previous-enabled'):
|
||||||
|
conditions.append(dataframe['fastd-previous'] < params['fastd-previous-value'])
|
||||||
|
|
||||||
|
if params.get('slowfastk-previous-enabled'):
|
||||||
|
conditions.append(dataframe['slowfastk-previous'] <
|
||||||
|
params['slowfastk-previous-value'])
|
||||||
|
if params.get('slowfastd-previous-enabled'):
|
||||||
|
conditions.append(dataframe['slowfastd-previous'] <
|
||||||
|
params['slowfastd-previous-value'])
|
||||||
|
|
||||||
|
if params.get('mean_volume-enabled'):
|
||||||
|
conditions.append(dataframe['mean-volume'] < params['mean-volume-value'])
|
||||||
|
|
||||||
|
if params.get('close-enabled'):
|
||||||
|
conditions.append(dataframe['close'] < params['close-value'])
|
||||||
|
|
||||||
|
# TRIGGERS
|
||||||
|
if 'trigger' in params:
|
||||||
|
if params['trigger'] == 'fast-previous':
|
||||||
|
conditions.append(dataframe['fastk-previous'] < dataframe['fastd-previous'])
|
||||||
|
if params['trigger'] == 'fast':
|
||||||
|
conditions.append(dataframe['fastk'] > dataframe['fastd'])
|
||||||
|
|
||||||
|
# Check that the candle had volume
|
||||||
|
conditions.append(dataframe['volume'] > 0)
|
||||||
|
|
||||||
|
if conditions:
|
||||||
|
dataframe.loc[
|
||||||
|
reduce(lambda x, y: x & y, conditions),
|
||||||
|
'buy'] = 1
|
||||||
|
|
||||||
|
return dataframe
|
||||||
|
|
||||||
|
return populate_buy_trend
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def indicator_space() -> List[Dimension]:
|
||||||
|
"""
|
||||||
|
Define your Hyperopt space for searching buy strategy parameters.
|
||||||
|
"""
|
||||||
|
return [
|
||||||
|
Integer(0, 100, name='adx-value'),
|
||||||
|
Integer(-150, -50, name='cci-value'),
|
||||||
|
Integer(0, 50, name='fastk-previous-value'),
|
||||||
|
Integer(0, 50, name='fastd-previous-value'),
|
||||||
|
Integer(0, 50, name='slowfastk-previous-value'),
|
||||||
|
Integer(0, 50, name='slowfastd-previous-value'),
|
||||||
|
Integer(0.0, 1.5, name='mean-volume-value'),
|
||||||
|
Integer(0.00000000, 0.00000500, name='close-value'),
|
||||||
|
Categorical([True, False], name='adx-enabled'),
|
||||||
|
Categorical([True, False], name='cci-enabled'),
|
||||||
|
Categorical([True, False], name='fastk-previous-enabled'),
|
||||||
|
Categorical([True, False], name='fastd-previous-enabled'),
|
||||||
|
Categorical([True, False], name='slowfastk-previous-enabled'),
|
||||||
|
Categorical([True, False], name='slowfastd-previous-enabled'),
|
||||||
|
Categorical([True, False], name='mean-volume-enabled'),
|
||||||
|
Categorical([True, False], name='close-enabled'),
|
||||||
|
Categorical(['fast', 'fast-previous'], name='trigger')
|
||||||
|
]
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def sell_strategy_generator(params: Dict[str, Any]) -> Callable:
|
||||||
|
"""
|
||||||
|
Define the sell strategy parameters to be used by Hyperopt.
|
||||||
|
"""
|
||||||
|
def populate_sell_trend(dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||||
|
"""
|
||||||
|
Sell strategy Hyperopt will build and use.
|
||||||
|
"""
|
||||||
|
conditions = []
|
||||||
|
|
||||||
|
# GUARDS AND TRENDS
|
||||||
|
if params.get('sell-slowadx-enabled'):
|
||||||
|
conditions.append(dataframe['slowadx'] < dataframe['sell-slowadx-value'])
|
||||||
|
if params.get('sell-fast-enabled'):
|
||||||
|
conditions.append((dataframe['fastk'] > dataframe['sell-fastk-value'])
|
||||||
|
| (dataframe['fastd'] > dataframe['sell-fastd-value']))
|
||||||
|
|
||||||
|
# TRIGGERS
|
||||||
|
if 'sell-trigger' in params:
|
||||||
|
if params['sell-trigger'] == 'sell-fast-previous':
|
||||||
|
conditions.append(dataframe['fastk-previous'] < dataframe['fastd-previous'])
|
||||||
|
if params['sell-trigger'] == 'sell-ema':
|
||||||
|
conditions.append(dataframe['close'] > dataframe['ema5'])
|
||||||
|
|
||||||
|
# Check that the candle had volume
|
||||||
|
conditions.append(dataframe['volume'] > 0)
|
||||||
|
|
||||||
|
if conditions:
|
||||||
|
dataframe.loc[
|
||||||
|
reduce(lambda x, y: x & y, conditions),
|
||||||
|
'sell'] = 1
|
||||||
|
|
||||||
|
return dataframe
|
||||||
|
|
||||||
|
return populate_sell_trend
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def sell_indicator_space() -> List[Dimension]:
|
||||||
|
"""
|
||||||
|
Define your Hyperopt space for searching sell strategy parameters.
|
||||||
|
"""
|
||||||
|
return [
|
||||||
|
Integer(0, 50, name='sell-slowadx-value'),
|
||||||
|
Integer(50, 100, name='sell-fastk-value'),
|
||||||
|
Integer(50, 100, name='sell-fastd-value'),
|
||||||
|
Categorical([True, False], name='sell-slowadx-enabled'),
|
||||||
|
Categorical([True, False], name='sell-fast-enabled'),
|
||||||
|
Categorical(['sell-ema', 'sell-fast-previous'], name='sell-trigger')
|
||||||
|
]
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def generate_roi_table(params: Dict) -> Dict[int, float]:
|
||||||
|
"""
|
||||||
|
Generate the ROI table that will be used by Hyperopt
|
||||||
|
This implementation generates the default legacy Freqtrade ROI tables.
|
||||||
|
Change it if you need different number of steps in the generated
|
||||||
|
ROI tables or other structure of the ROI tables.
|
||||||
|
Please keep it aligned with parameters in the 'roi' optimization
|
||||||
|
hyperspace defined by the roi_space method.
|
||||||
|
"""
|
||||||
|
roi_table = {}
|
||||||
|
roi_table[0] = params['roi_p1'] + params['roi_p2'] + params['roi_p3']
|
||||||
|
roi_table[params['roi_t3']] = params['roi_p1'] + params['roi_p2']
|
||||||
|
roi_table[params['roi_t3'] + params['roi_t2']] = params['roi_p1']
|
||||||
|
roi_table[params['roi_t3'] + params['roi_t2'] + params['roi_t1']] = 0
|
||||||
|
|
||||||
|
return roi_table
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def roi_space() -> List[Dimension]:
|
||||||
|
"""
|
||||||
|
Values to search for each ROI steps
|
||||||
|
Override it if you need some different ranges for the parameters in the
|
||||||
|
'roi' optimization hyperspace.
|
||||||
|
Please keep it aligned with the implementation of the
|
||||||
|
generate_roi_table method.
|
||||||
|
"""
|
||||||
|
return [
|
||||||
|
Integer(10, 120, name='roi_t1'),
|
||||||
|
Integer(10, 60, name='roi_t2'),
|
||||||
|
Integer(10, 40, name='roi_t3'),
|
||||||
|
Real(0.01, 0.04, name='roi_p1'),
|
||||||
|
Real(0.01, 0.07, name='roi_p2'),
|
||||||
|
Real(0.01, 0.20, name='roi_p3'),
|
||||||
|
]
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def stoploss_space() -> List[Dimension]:
|
||||||
|
"""
|
||||||
|
Stoploss Value to search
|
||||||
|
Override it if you need some different range for the parameter in the
|
||||||
|
'stoploss' optimization hyperspace.
|
||||||
|
"""
|
||||||
|
return [
|
||||||
|
Real(-0.35, -0.02, name='stoploss'),
|
||||||
|
]
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def trailing_space() -> List[Dimension]:
|
||||||
|
"""
|
||||||
|
Create a trailing stoploss space.
|
||||||
|
You may override it in your custom Hyperopt class.
|
||||||
|
"""
|
||||||
|
return [
|
||||||
|
# It was decided to always set trailing_stop is to True if the 'trailing' hyperspace
|
||||||
|
# is used. Otherwise hyperopt will vary other parameters that won't have effect if
|
||||||
|
# trailing_stop is set False.
|
||||||
|
# This parameter is included into the hyperspace dimensions rather than assigning
|
||||||
|
# it explicitly in the code in order to have it printed in the results along with
|
||||||
|
# other 'trailing' hyperspace parameters.
|
||||||
|
Categorical([True], name='trailing_stop'),
|
||||||
|
|
||||||
|
Real(0.01, 0.35, name='trailing_stop_positive'),
|
||||||
|
|
||||||
|
# 'trailing_stop_positive_offset' should be greater than 'trailing_stop_positive',
|
||||||
|
# so this intermediate parameter is used as the value of the difference between
|
||||||
|
# them. The value of the 'trailing_stop_positive_offset' is constructed in the
|
||||||
|
# generate_trailing_params() method.
|
||||||
|
# This is similar to the hyperspace dimensions used for constructing the ROI tables.
|
||||||
|
Real(0.001, 0.1, name='trailing_stop_positive_offset_p1'),
|
||||||
|
|
||||||
|
Categorical([True, False], name='trailing_only_offset_is_reached'),
|
||||||
|
]
|
||||||
|
|
||||||
|
def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||||
|
"""
|
||||||
|
Based on TA indicators, populates the buy signal for the given dataframe
|
||||||
|
:param dataframe: DataFrame
|
||||||
|
:return: DataFrame with buy column
|
||||||
|
"""
|
||||||
|
dataframe.loc[
|
||||||
|
(
|
||||||
|
(
|
||||||
|
(dataframe['adx'] > 50) |
|
||||||
|
(dataframe['slowadx'] > 26)
|
||||||
|
) &
|
||||||
|
(dataframe['cci'] < -100) &
|
||||||
|
(
|
||||||
|
(dataframe['fastk-previous'] < 20) &
|
||||||
|
(dataframe['fastd-previous'] < 20)
|
||||||
|
) &
|
||||||
|
(
|
||||||
|
(dataframe['slowfastk-previous'] < 30) &
|
||||||
|
(dataframe['slowfastd-previous'] < 30)
|
||||||
|
) &
|
||||||
|
(dataframe['fastk-previous'] < dataframe['fastd-previous']) &
|
||||||
|
(dataframe['fastk'] > dataframe['fastd']) &
|
||||||
|
(dataframe['mean-volume'] > 0.75) &
|
||||||
|
(dataframe['close'] > 0.00000100)
|
||||||
|
),
|
||||||
|
'buy'] = 1
|
||||||
|
|
||||||
|
return dataframe
|
||||||
|
|
||||||
|
def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||||
|
"""
|
||||||
|
Based on TA indicators, populates the sell signal for the given dataframe
|
||||||
|
:param dataframe: DataFrame
|
||||||
|
:return: DataFrame with buy column
|
||||||
|
"""
|
||||||
|
dataframe.loc[
|
||||||
|
(
|
||||||
|
(dataframe['slowadx'] < 25) &
|
||||||
|
((dataframe['fastk'] > 70) | (dataframe['fastd'] > 70)) &
|
||||||
|
(dataframe['fastk-previous'] < dataframe['fastd-previous']) &
|
||||||
|
(dataframe['close'] > dataframe['ema5'])
|
||||||
|
),
|
||||||
|
'sell'] = 1
|
||||||
|
return dataframe
|
290
user_data/hyperopts/examplefreqtrade5opt.py
Normal file
290
user_data/hyperopts/examplefreqtrade5opt.py
Normal file
@ -0,0 +1,290 @@
|
|||||||
|
# pragma pylint: disable=missing-docstring, invalid-name, pointless-string-statement
|
||||||
|
|
||||||
|
# --- Do not remove these libs ---
|
||||||
|
from functools import reduce
|
||||||
|
from typing import Any, Callable, Dict, List
|
||||||
|
|
||||||
|
import numpy # noqa
|
||||||
|
import pandas # noqa
|
||||||
|
from pandas import DataFrame
|
||||||
|
from skopt.space import Categorical, Dimension, Integer, Real # noqa
|
||||||
|
|
||||||
|
from freqtrade.optimize.hyperopt_interface import IHyperOpt
|
||||||
|
|
||||||
|
# --------------------------------
|
||||||
|
# Add your lib to import here
|
||||||
|
import talib.abstract as ta # noqa
|
||||||
|
import freqtrade.vendor.qtpylib.indicators as qtpylib
|
||||||
|
|
||||||
|
|
||||||
|
class Examplestrategy5opt(IHyperOpt):
|
||||||
|
@staticmethod
|
||||||
|
def populate_indicators(dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||||
|
"""
|
||||||
|
Adds several different TA indicators to the given DataFrame
|
||||||
|
Performance Note: For the best performance be frugal on the number of indicators
|
||||||
|
you are using. Let uncomment only the indicator you are using in your strategies
|
||||||
|
or your hyperopt configuration, otherwise you will waste your memory and CPU usage.
|
||||||
|
"""
|
||||||
|
|
||||||
|
# MACD
|
||||||
|
macd = ta.MACD(dataframe)
|
||||||
|
dataframe['macd'] = macd['macd']
|
||||||
|
dataframe['macdsignal'] = macd['macdsignal']
|
||||||
|
|
||||||
|
# Minus Directional Indicator / Movement
|
||||||
|
dataframe['minus_di'] = ta.MINUS_DI(dataframe)
|
||||||
|
|
||||||
|
# RSI
|
||||||
|
dataframe['rsi'] = ta.RSI(dataframe)
|
||||||
|
|
||||||
|
# Inverse Fisher transform on RSI, values [-1.0, 1.0] (https://goo.gl/2JGGoy)
|
||||||
|
rsi = 0.1 * (dataframe['rsi'] - 50)
|
||||||
|
dataframe['fisher_rsi'] = (numpy.exp(2 * rsi) - 1) / (numpy.exp(2 * rsi) + 1)
|
||||||
|
# Inverse Fisher transform on RSI normalized, value [0.0, 100.0] (https://goo.gl/2JGGoy)
|
||||||
|
dataframe['fisher_rsi_norma'] = 50 * (dataframe['fisher_rsi'] + 1)
|
||||||
|
|
||||||
|
# Stoch fast
|
||||||
|
stoch_fast = ta.STOCHF(dataframe)
|
||||||
|
dataframe['fastd'] = stoch_fast['fastd']
|
||||||
|
dataframe['fastk'] = stoch_fast['fastk']
|
||||||
|
|
||||||
|
# Overlap Studies
|
||||||
|
# ------------------------------------
|
||||||
|
|
||||||
|
# SAR Parabol
|
||||||
|
dataframe['sar'] = ta.SAR(dataframe)
|
||||||
|
|
||||||
|
# SMA - Simple Moving Average
|
||||||
|
dataframe['sma'] = ta.SMA(dataframe, timeperiod=40)
|
||||||
|
|
||||||
|
return dataframe
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def buy_strategy_generator(params: Dict[str, Any]) -> Callable:
|
||||||
|
"""
|
||||||
|
Define the buy strategy parameters to be used by Hyperopt.
|
||||||
|
"""
|
||||||
|
def populate_buy_trend(dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||||
|
"""
|
||||||
|
Buy strategy Hyperopt will build and use.
|
||||||
|
"""
|
||||||
|
conditions = []
|
||||||
|
|
||||||
|
# GUARDS AND TRENDS
|
||||||
|
if params.get('fastd-enabled'):
|
||||||
|
conditions.append(dataframe['fastd'] > params['fastd-value'])
|
||||||
|
|
||||||
|
if params.get('rsi-enabled'):
|
||||||
|
conditions.append(dataframe['rsi'] > params['rsi-value'])
|
||||||
|
|
||||||
|
if params.get('close-enabled'):
|
||||||
|
conditions.append(dataframe['close'] > params['close-value'])
|
||||||
|
|
||||||
|
if params.get('fisher_rsi_norma-enabled'):
|
||||||
|
conditions.append(dataframe['fisher_rsi_norma'] < params['fisher_rsi_norma-value'])
|
||||||
|
|
||||||
|
# TRIGGERS
|
||||||
|
if 'trigger' in params:
|
||||||
|
if params['trigger'] == 'sma':
|
||||||
|
conditions.append(dataframe['close'] < dataframe['sma'])
|
||||||
|
if params['trigger'] == 'fast':
|
||||||
|
conditions.append(dataframe['fastk'] < dataframe['fastd'])
|
||||||
|
if params['trigger'] == 'volume':
|
||||||
|
conditions.append(dataframe['volume'] >
|
||||||
|
dataframe['volume'].rolling(200).mean() * 4)
|
||||||
|
|
||||||
|
# Check that the candle had volume
|
||||||
|
conditions.append(dataframe['volume'] > 0)
|
||||||
|
|
||||||
|
if conditions:
|
||||||
|
dataframe.loc[
|
||||||
|
reduce(lambda x, y: x & y, conditions),
|
||||||
|
'buy'] = 1
|
||||||
|
|
||||||
|
return dataframe
|
||||||
|
|
||||||
|
return populate_buy_trend
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def indicator_space() -> List[Dimension]:
|
||||||
|
"""
|
||||||
|
Define your Hyperopt space for searching buy strategy parameters.
|
||||||
|
"""
|
||||||
|
return [
|
||||||
|
Integer(0, 50, name='rsi-value'),
|
||||||
|
Integer(0.0, 100.0, name='fisher_rsi_norma-value'),
|
||||||
|
Integer(0, 50, name='fastd-value'),
|
||||||
|
Integer(0.00000000, 0.00000200, name='close-value'),
|
||||||
|
Categorical([True, False], name='rsi-enabled'),
|
||||||
|
Categorical([True, False], name='fastd-enabled'),
|
||||||
|
Categorical([True, False], name='fisher_rsi_norma-enabled'),
|
||||||
|
Categorical([True, False], name='close-enabled'),
|
||||||
|
Categorical(['fast', 'sma', 'volume'], name='trigger')
|
||||||
|
]
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def sell_strategy_generator(params: Dict[str, Any]) -> Callable:
|
||||||
|
"""
|
||||||
|
Define the sell strategy parameters to be used by Hyperopt.
|
||||||
|
"""
|
||||||
|
def populate_sell_trend(dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||||
|
"""
|
||||||
|
Sell strategy Hyperopt will build and use.
|
||||||
|
"""
|
||||||
|
conditions = []
|
||||||
|
|
||||||
|
# GUARDS AND TRENDS
|
||||||
|
if params.get('sell-enabled'):
|
||||||
|
conditions.append(
|
||||||
|
(
|
||||||
|
(qtpylib.crossed_above(dataframe['rsi'], dataframe['sell-rsi-value'])) &
|
||||||
|
(dataframe['macd'] < dataframe['sell-macd-value']) &
|
||||||
|
(dataframe['minus_di'] > dataframe['sell-minus_di-value'])
|
||||||
|
) |
|
||||||
|
(
|
||||||
|
(dataframe['sar'] > dataframe['close']) &
|
||||||
|
(dataframe['fisher_rsi'] > dataframe['sell-fisher_rsi-value'])
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
# Check that the candle had volume
|
||||||
|
conditions.append(dataframe['volume'] > 0)
|
||||||
|
|
||||||
|
if conditions:
|
||||||
|
dataframe.loc[
|
||||||
|
reduce(lambda x, y: x & y, conditions),
|
||||||
|
'sell'] = 1
|
||||||
|
|
||||||
|
return dataframe
|
||||||
|
|
||||||
|
return populate_sell_trend
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def sell_indicator_space() -> List[Dimension]:
|
||||||
|
"""
|
||||||
|
Define your Hyperopt space for searching sell strategy parameters.
|
||||||
|
"""
|
||||||
|
return [
|
||||||
|
Integer(25, 75, name='sell-rsi-value'),
|
||||||
|
Integer(-50, 50, name='sell-macd-value'),
|
||||||
|
Integer(-50, 50, name='sell-minus_di-value'),
|
||||||
|
Categorical([True, False], name='sell-enabled'),
|
||||||
|
]
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def generate_roi_table(params: Dict) -> Dict[int, float]:
|
||||||
|
"""
|
||||||
|
Generate the ROI table that will be used by Hyperopt
|
||||||
|
This implementation generates the default legacy Freqtrade ROI tables.
|
||||||
|
Change it if you need different number of steps in the generated
|
||||||
|
ROI tables or other structure of the ROI tables.
|
||||||
|
Please keep it aligned with parameters in the 'roi' optimization
|
||||||
|
hyperspace defined by the roi_space method.
|
||||||
|
"""
|
||||||
|
roi_table = {}
|
||||||
|
roi_table[0] = params['roi_p1'] + params['roi_p2'] + params['roi_p3']
|
||||||
|
roi_table[params['roi_t3']] = params['roi_p1'] + params['roi_p2']
|
||||||
|
roi_table[params['roi_t3'] + params['roi_t2']] = params['roi_p1']
|
||||||
|
roi_table[params['roi_t3'] + params['roi_t2'] + params['roi_t1']] = 0
|
||||||
|
|
||||||
|
return roi_table
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def roi_space() -> List[Dimension]:
|
||||||
|
"""
|
||||||
|
Values to search for each ROI steps
|
||||||
|
Override it if you need some different ranges for the parameters in the
|
||||||
|
'roi' optimization hyperspace.
|
||||||
|
Please keep it aligned with the implementation of the
|
||||||
|
generate_roi_table method.
|
||||||
|
"""
|
||||||
|
return [
|
||||||
|
Integer(10, 120, name='roi_t1'),
|
||||||
|
Integer(10, 60, name='roi_t2'),
|
||||||
|
Integer(10, 40, name='roi_t3'),
|
||||||
|
Real(0.01, 0.04, name='roi_p1'),
|
||||||
|
Real(0.01, 0.07, name='roi_p2'),
|
||||||
|
Real(0.01, 0.20, name='roi_p3'),
|
||||||
|
]
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def stoploss_space() -> List[Dimension]:
|
||||||
|
"""
|
||||||
|
Stoploss Value to search
|
||||||
|
Override it if you need some different range for the parameter in the
|
||||||
|
'stoploss' optimization hyperspace.
|
||||||
|
"""
|
||||||
|
return [
|
||||||
|
Real(-0.35, -0.02, name='stoploss'),
|
||||||
|
]
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def trailing_space() -> List[Dimension]:
|
||||||
|
"""
|
||||||
|
Create a trailing stoploss space.
|
||||||
|
You may override it in your custom Hyperopt class.
|
||||||
|
"""
|
||||||
|
return [
|
||||||
|
# It was decided to always set trailing_stop is to True if the 'trailing' hyperspace
|
||||||
|
# is used. Otherwise hyperopt will vary other parameters that won't have effect if
|
||||||
|
# trailing_stop is set False.
|
||||||
|
# This parameter is included into the hyperspace dimensions rather than assigning
|
||||||
|
# it explicitly in the code in order to have it printed in the results along with
|
||||||
|
# other 'trailing' hyperspace parameters.
|
||||||
|
Categorical([True], name='trailing_stop'),
|
||||||
|
|
||||||
|
Real(0.01, 0.35, name='trailing_stop_positive'),
|
||||||
|
|
||||||
|
# 'trailing_stop_positive_offset' should be greater than 'trailing_stop_positive',
|
||||||
|
# so this intermediate parameter is used as the value of the difference between
|
||||||
|
# them. The value of the 'trailing_stop_positive_offset' is constructed in the
|
||||||
|
# generate_trailing_params() method.
|
||||||
|
# This is similar to the hyperspace dimensions used for constructing the ROI tables.
|
||||||
|
Real(0.001, 0.1, name='trailing_stop_positive_offset_p1'),
|
||||||
|
|
||||||
|
Categorical([True, False], name='trailing_only_offset_is_reached'),
|
||||||
|
]
|
||||||
|
|
||||||
|
def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||||
|
"""
|
||||||
|
Based on TA indicators, populates the buy signal for the given dataframe
|
||||||
|
:param dataframe: DataFrame
|
||||||
|
:return: DataFrame with buy column
|
||||||
|
"""
|
||||||
|
dataframe.loc[
|
||||||
|
# Prod
|
||||||
|
(
|
||||||
|
(dataframe['close'] > 0.00000200) &
|
||||||
|
(dataframe['volume'] > dataframe['volume'].rolling(200).mean() * 4) &
|
||||||
|
(dataframe['close'] < dataframe['sma']) &
|
||||||
|
(dataframe['fastd'] > dataframe['fastk']) &
|
||||||
|
(dataframe['rsi'] > 0) &
|
||||||
|
(dataframe['fastd'] > 0) &
|
||||||
|
# (dataframe['fisher_rsi'] < -0.94)
|
||||||
|
(dataframe['fisher_rsi_norma'] < 38.900000000000006)
|
||||||
|
),
|
||||||
|
'buy'] = 1
|
||||||
|
|
||||||
|
return dataframe
|
||||||
|
|
||||||
|
def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||||
|
"""
|
||||||
|
Based on TA indicators, populates the sell signal for the given dataframe
|
||||||
|
:param dataframe: DataFrame
|
||||||
|
:return: DataFrame with buy column
|
||||||
|
"""
|
||||||
|
dataframe.loc[
|
||||||
|
# Prod
|
||||||
|
(
|
||||||
|
(qtpylib.crossed_above(dataframe['rsi'], 50)) &
|
||||||
|
(dataframe['macd'] < 0) &
|
||||||
|
(dataframe['minus_di'] > 0)
|
||||||
|
) |
|
||||||
|
(
|
||||||
|
(dataframe['sar'] > dataframe['close']) &
|
||||||
|
(dataframe['fisher_rsi'] > 0.3)
|
||||||
|
),
|
||||||
|
|
||||||
|
'sell'] = 1
|
||||||
|
return dataframe
|
364
user_data/strategies/BasicStrategy.py
Normal file
364
user_data/strategies/BasicStrategy.py
Normal file
@ -0,0 +1,364 @@
|
|||||||
|
# pragma pylint: disable=missing-docstring, invalid-name, pointless-string-statement
|
||||||
|
|
||||||
|
# --- Do not remove these libs ---
|
||||||
|
import numpy # noqa
|
||||||
|
import pandas # noqa
|
||||||
|
from pandas import DataFrame
|
||||||
|
|
||||||
|
from freqtrade.strategy.interface import IStrategy
|
||||||
|
|
||||||
|
# --------------------------------
|
||||||
|
# Add your lib to import here
|
||||||
|
import talib.abstract as ta
|
||||||
|
import freqtrade.vendor.qtpylib.indicators as qtpylib
|
||||||
|
|
||||||
|
|
||||||
|
class BasicStrategy(IStrategy):
|
||||||
|
"""
|
||||||
|
This is a strategy template to get you started.
|
||||||
|
More information in https://github.com/freqtrade/freqtrade/blob/develop/docs/bot-optimization.md
|
||||||
|
|
||||||
|
You can:
|
||||||
|
:return: a Dataframe with all mandatory indicators for the strategies
|
||||||
|
- Rename the class name (Do not forget to update class_name)
|
||||||
|
- Add any methods you want to build your strategy
|
||||||
|
- Add any lib you need to build your strategy
|
||||||
|
|
||||||
|
You must keep:
|
||||||
|
- the lib in the section "Do not remove these libs"
|
||||||
|
- the prototype for the methods: minimal_roi, stoploss, populate_indicators, populate_buy_trend,
|
||||||
|
populate_sell_trend, hyperopt_space, buy_strategy_generator
|
||||||
|
"""
|
||||||
|
# Strategy interface version - allow new iterations of the strategy interface.
|
||||||
|
# Check the documentation or the Sample strategy to get the latest version.
|
||||||
|
INTERFACE_VERSION = 2
|
||||||
|
|
||||||
|
# Minimal ROI designed for the strategy.
|
||||||
|
# This attribute will be overridden if the config file contains "minimal_roi".
|
||||||
|
minimal_roi = {
|
||||||
|
"60": 0.01,
|
||||||
|
"30": 0.02,
|
||||||
|
"0": 0.04
|
||||||
|
}
|
||||||
|
|
||||||
|
# Optimal stoploss designed for the strategy.
|
||||||
|
# This attribute will be overridden if the config file contains "stoploss".
|
||||||
|
stoploss = -0.10
|
||||||
|
|
||||||
|
# Trailing stoploss
|
||||||
|
trailing_stop = False
|
||||||
|
# trailing_only_offset_is_reached = False
|
||||||
|
# trailing_stop_positive = 0.01
|
||||||
|
# trailing_stop_positive_offset = 0.0 # Disabled / not configured
|
||||||
|
|
||||||
|
# Optimal timeframe for the strategy.
|
||||||
|
timeframe = '5m'
|
||||||
|
|
||||||
|
# Run "populate_indicators()" only for new candle.
|
||||||
|
process_only_new_candles = False
|
||||||
|
|
||||||
|
# These values can be overridden in the "ask_strategy" section in the config.
|
||||||
|
use_sell_signal = True
|
||||||
|
sell_profit_only = False
|
||||||
|
ignore_roi_if_buy_signal = False
|
||||||
|
|
||||||
|
# Number of candles the strategy requires before producing valid signals
|
||||||
|
startup_candle_count: int = 20
|
||||||
|
|
||||||
|
# Optional order type mapping.
|
||||||
|
order_types = {
|
||||||
|
'buy': 'limit',
|
||||||
|
'sell': 'limit',
|
||||||
|
'stoploss': 'market',
|
||||||
|
'stoploss_on_exchange': False
|
||||||
|
}
|
||||||
|
|
||||||
|
# Optional order time in force.
|
||||||
|
order_time_in_force = {
|
||||||
|
'buy': 'gtc',
|
||||||
|
'sell': 'gtc'
|
||||||
|
}
|
||||||
|
|
||||||
|
plot_config = {
|
||||||
|
# Main plot indicators (Moving averages, ...)
|
||||||
|
'main_plot': {
|
||||||
|
'tema': {},
|
||||||
|
'sar': {'color': 'white'},
|
||||||
|
},
|
||||||
|
'subplots': {
|
||||||
|
# Subplots - each dict defines one additional plot
|
||||||
|
"MACD": {
|
||||||
|
'macd': {'color': 'blue'},
|
||||||
|
'macdsignal': {'color': 'orange'},
|
||||||
|
},
|
||||||
|
"RSI": {
|
||||||
|
'rsi': {'color': 'red'},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
def informative_pairs(self):
|
||||||
|
"""
|
||||||
|
Define additional, informative pair/interval combinations to be cached from the exchange.
|
||||||
|
These pair/interval combinations are non-tradeable, unless they are part
|
||||||
|
of the whitelist as well.
|
||||||
|
For more information, please consult the documentation
|
||||||
|
:return: List of tuples in the format (pair, interval)
|
||||||
|
Sample: return [("ETH/USDT", "5m"),
|
||||||
|
("BTC/USDT", "15m"),
|
||||||
|
]
|
||||||
|
"""
|
||||||
|
return []
|
||||||
|
|
||||||
|
def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||||
|
"""
|
||||||
|
Adds several different TA indicators to the given DataFrame
|
||||||
|
|
||||||
|
Performance Note: For the best performance be frugal on the number of indicators
|
||||||
|
you are using. Let uncomment only the indicator you are using in your strategies
|
||||||
|
or your hyperopt configuration, otherwise you will waste your memory and CPU usage.
|
||||||
|
:param dataframe: Dataframe with data from the exchange
|
||||||
|
:param metadata: Additional information, like the currently traded pair
|
||||||
|
:return: a Dataframe with all mandatory indicators for the strategies
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Momentum Indicators
|
||||||
|
# ------------------------------------
|
||||||
|
|
||||||
|
# ADX
|
||||||
|
dataframe['adx'] = ta.ADX(dataframe)
|
||||||
|
|
||||||
|
# # Plus Directional Indicator / Movement
|
||||||
|
# dataframe['plus_dm'] = ta.PLUS_DM(dataframe)
|
||||||
|
# dataframe['plus_di'] = ta.PLUS_DI(dataframe)
|
||||||
|
|
||||||
|
# # Minus Directional Indicator / Movement
|
||||||
|
# dataframe['minus_dm'] = ta.MINUS_DM(dataframe)
|
||||||
|
# dataframe['minus_di'] = ta.MINUS_DI(dataframe)
|
||||||
|
|
||||||
|
# # Aroon, Aroon Oscillator
|
||||||
|
# aroon = ta.AROON(dataframe)
|
||||||
|
# dataframe['aroonup'] = aroon['aroonup']
|
||||||
|
# dataframe['aroondown'] = aroon['aroondown']
|
||||||
|
# dataframe['aroonosc'] = ta.AROONOSC(dataframe)
|
||||||
|
|
||||||
|
# # Awesome Oscillator
|
||||||
|
# dataframe['ao'] = qtpylib.awesome_oscillator(dataframe)
|
||||||
|
|
||||||
|
# # Keltner Channel
|
||||||
|
# keltner = qtpylib.keltner_channel(dataframe)
|
||||||
|
# dataframe["kc_upperband"] = keltner["upper"]
|
||||||
|
# dataframe["kc_lowerband"] = keltner["lower"]
|
||||||
|
# dataframe["kc_middleband"] = keltner["mid"]
|
||||||
|
# dataframe["kc_percent"] = (
|
||||||
|
# (dataframe["close"] - dataframe["kc_lowerband"]) /
|
||||||
|
# (dataframe["kc_upperband"] - dataframe["kc_lowerband"])
|
||||||
|
# )
|
||||||
|
# dataframe["kc_width"] = (
|
||||||
|
# (dataframe["kc_upperband"] - dataframe["kc_lowerband"]) / dataframe["kc_middleband"]
|
||||||
|
# )
|
||||||
|
|
||||||
|
# # Ultimate Oscillator
|
||||||
|
# dataframe['uo'] = ta.ULTOSC(dataframe)
|
||||||
|
|
||||||
|
# # Commodity Channel Index: values [Oversold:-100, Overbought:100]
|
||||||
|
# dataframe['cci'] = ta.CCI(dataframe)
|
||||||
|
|
||||||
|
# RSI
|
||||||
|
dataframe['rsi'] = ta.RSI(dataframe)
|
||||||
|
|
||||||
|
# # Inverse Fisher transform on RSI: values [-1.0, 1.0] (https://goo.gl/2JGGoy)
|
||||||
|
# rsi = 0.1 * (dataframe['rsi'] - 50)
|
||||||
|
# dataframe['fisher_rsi'] = (np.exp(2 * rsi) - 1) / (np.exp(2 * rsi) + 1)
|
||||||
|
|
||||||
|
# # Inverse Fisher transform on RSI normalized: values [0.0, 100.0] (https://goo.gl/2JGGoy)
|
||||||
|
# dataframe['fisher_rsi_norma'] = 50 * (dataframe['fisher_rsi'] + 1)
|
||||||
|
|
||||||
|
# # Stochastic Slow
|
||||||
|
# stoch = ta.STOCH(dataframe)
|
||||||
|
# dataframe['slowd'] = stoch['slowd']
|
||||||
|
# dataframe['slowk'] = stoch['slowk']
|
||||||
|
|
||||||
|
# Stochastic Fast
|
||||||
|
stoch_fast = ta.STOCHF(dataframe)
|
||||||
|
dataframe['fastd'] = stoch_fast['fastd']
|
||||||
|
dataframe['fastk'] = stoch_fast['fastk']
|
||||||
|
|
||||||
|
# # Stochastic RSI
|
||||||
|
# stoch_rsi = ta.STOCHRSI(dataframe)
|
||||||
|
# dataframe['fastd_rsi'] = stoch_rsi['fastd']
|
||||||
|
# dataframe['fastk_rsi'] = stoch_rsi['fastk']
|
||||||
|
|
||||||
|
# MACD
|
||||||
|
macd = ta.MACD(dataframe)
|
||||||
|
dataframe['macd'] = macd['macd']
|
||||||
|
dataframe['macdsignal'] = macd['macdsignal']
|
||||||
|
dataframe['macdhist'] = macd['macdhist']
|
||||||
|
|
||||||
|
# MFI
|
||||||
|
dataframe['mfi'] = ta.MFI(dataframe)
|
||||||
|
|
||||||
|
# # ROC
|
||||||
|
# dataframe['roc'] = ta.ROC(dataframe)
|
||||||
|
|
||||||
|
# Overlap Studies
|
||||||
|
# ------------------------------------
|
||||||
|
|
||||||
|
# Bollinger Bands
|
||||||
|
bollinger = qtpylib.bollinger_bands(qtpylib.typical_price(dataframe), window=20, stds=2)
|
||||||
|
dataframe['bb_lowerband'] = bollinger['lower']
|
||||||
|
dataframe['bb_middleband'] = bollinger['mid']
|
||||||
|
dataframe['bb_upperband'] = bollinger['upper']
|
||||||
|
dataframe["bb_percent"] = (
|
||||||
|
(dataframe["close"] - dataframe["bb_lowerband"]) /
|
||||||
|
(dataframe["bb_upperband"] - dataframe["bb_lowerband"])
|
||||||
|
)
|
||||||
|
dataframe["bb_width"] = (
|
||||||
|
(dataframe["bb_upperband"] - dataframe["bb_lowerband"]) / dataframe["bb_middleband"]
|
||||||
|
)
|
||||||
|
|
||||||
|
# Bollinger Bands - Weighted (EMA based instead of SMA)
|
||||||
|
# weighted_bollinger = qtpylib.weighted_bollinger_bands(
|
||||||
|
# qtpylib.typical_price(dataframe), window=20, stds=2
|
||||||
|
# )
|
||||||
|
# dataframe["wbb_upperband"] = weighted_bollinger["upper"]
|
||||||
|
# dataframe["wbb_lowerband"] = weighted_bollinger["lower"]
|
||||||
|
# dataframe["wbb_middleband"] = weighted_bollinger["mid"]
|
||||||
|
# dataframe["wbb_percent"] = (
|
||||||
|
# (dataframe["close"] - dataframe["wbb_lowerband"]) /
|
||||||
|
# (dataframe["wbb_upperband"] - dataframe["wbb_lowerband"])
|
||||||
|
# )
|
||||||
|
# dataframe["wbb_width"] = (
|
||||||
|
# (dataframe["wbb_upperband"] - dataframe["wbb_lowerband"]) / dataframe["wbb_middleband"]
|
||||||
|
# )
|
||||||
|
|
||||||
|
# # EMA - Exponential Moving Average
|
||||||
|
# dataframe['ema3'] = ta.EMA(dataframe, timeperiod=3)
|
||||||
|
# dataframe['ema5'] = ta.EMA(dataframe, timeperiod=5)
|
||||||
|
# dataframe['ema10'] = ta.EMA(dataframe, timeperiod=10)
|
||||||
|
# dataframe['ema21'] = ta.EMA(dataframe, timeperiod=21)
|
||||||
|
# dataframe['ema50'] = ta.EMA(dataframe, timeperiod=50)
|
||||||
|
# dataframe['ema100'] = ta.EMA(dataframe, timeperiod=100)
|
||||||
|
|
||||||
|
# # SMA - Simple Moving Average
|
||||||
|
# dataframe['sma3'] = ta.SMA(dataframe, timeperiod=3)
|
||||||
|
# dataframe['sma5'] = ta.SMA(dataframe, timeperiod=5)
|
||||||
|
# dataframe['sma10'] = ta.SMA(dataframe, timeperiod=10)
|
||||||
|
# dataframe['sma21'] = ta.SMA(dataframe, timeperiod=21)
|
||||||
|
# dataframe['sma50'] = ta.SMA(dataframe, timeperiod=50)
|
||||||
|
# dataframe['sma100'] = ta.SMA(dataframe, timeperiod=100)
|
||||||
|
|
||||||
|
# Parabolic SAR
|
||||||
|
dataframe['sar'] = ta.SAR(dataframe)
|
||||||
|
|
||||||
|
# TEMA - Triple Exponential Moving Average
|
||||||
|
dataframe['tema'] = ta.TEMA(dataframe, timeperiod=9)
|
||||||
|
|
||||||
|
# Cycle Indicator
|
||||||
|
# ------------------------------------
|
||||||
|
# Hilbert Transform Indicator - SineWave
|
||||||
|
hilbert = ta.HT_SINE(dataframe)
|
||||||
|
dataframe['htsine'] = hilbert['sine']
|
||||||
|
dataframe['htleadsine'] = hilbert['leadsine']
|
||||||
|
|
||||||
|
# Pattern Recognition - Bullish candlestick patterns
|
||||||
|
# ------------------------------------
|
||||||
|
# # Hammer: values [0, 100]
|
||||||
|
# dataframe['CDLHAMMER'] = ta.CDLHAMMER(dataframe)
|
||||||
|
# # Inverted Hammer: values [0, 100]
|
||||||
|
# dataframe['CDLINVERTEDHAMMER'] = ta.CDLINVERTEDHAMMER(dataframe)
|
||||||
|
# # Dragonfly Doji: values [0, 100]
|
||||||
|
# dataframe['CDLDRAGONFLYDOJI'] = ta.CDLDRAGONFLYDOJI(dataframe)
|
||||||
|
# # Piercing Line: values [0, 100]
|
||||||
|
# dataframe['CDLPIERCING'] = ta.CDLPIERCING(dataframe) # values [0, 100]
|
||||||
|
# # Morningstar: values [0, 100]
|
||||||
|
# dataframe['CDLMORNINGSTAR'] = ta.CDLMORNINGSTAR(dataframe) # values [0, 100]
|
||||||
|
# # Three White Soldiers: values [0, 100]
|
||||||
|
# dataframe['CDL3WHITESOLDIERS'] = ta.CDL3WHITESOLDIERS(dataframe) # values [0, 100]
|
||||||
|
|
||||||
|
# Pattern Recognition - Bearish candlestick patterns
|
||||||
|
# ------------------------------------
|
||||||
|
# # Hanging Man: values [0, 100]
|
||||||
|
# dataframe['CDLHANGINGMAN'] = ta.CDLHANGINGMAN(dataframe)
|
||||||
|
# # Shooting Star: values [0, 100]
|
||||||
|
# dataframe['CDLSHOOTINGSTAR'] = ta.CDLSHOOTINGSTAR(dataframe)
|
||||||
|
# # Gravestone Doji: values [0, 100]
|
||||||
|
# dataframe['CDLGRAVESTONEDOJI'] = ta.CDLGRAVESTONEDOJI(dataframe)
|
||||||
|
# # Dark Cloud Cover: values [0, 100]
|
||||||
|
# dataframe['CDLDARKCLOUDCOVER'] = ta.CDLDARKCLOUDCOVER(dataframe)
|
||||||
|
# # Evening Doji Star: values [0, 100]
|
||||||
|
# dataframe['CDLEVENINGDOJISTAR'] = ta.CDLEVENINGDOJISTAR(dataframe)
|
||||||
|
# # Evening Star: values [0, 100]
|
||||||
|
# dataframe['CDLEVENINGSTAR'] = ta.CDLEVENINGSTAR(dataframe)
|
||||||
|
|
||||||
|
# Pattern Recognition - Bullish/Bearish candlestick patterns
|
||||||
|
# ------------------------------------
|
||||||
|
# # Three Line Strike: values [0, -100, 100]
|
||||||
|
# dataframe['CDL3LINESTRIKE'] = ta.CDL3LINESTRIKE(dataframe)
|
||||||
|
# # Spinning Top: values [0, -100, 100]
|
||||||
|
# dataframe['CDLSPINNINGTOP'] = ta.CDLSPINNINGTOP(dataframe) # values [0, -100, 100]
|
||||||
|
# # Engulfing: values [0, -100, 100]
|
||||||
|
# dataframe['CDLENGULFING'] = ta.CDLENGULFING(dataframe) # values [0, -100, 100]
|
||||||
|
# # Harami: values [0, -100, 100]
|
||||||
|
# dataframe['CDLHARAMI'] = ta.CDLHARAMI(dataframe) # values [0, -100, 100]
|
||||||
|
# # Three Outside Up/Down: values [0, -100, 100]
|
||||||
|
# dataframe['CDL3OUTSIDE'] = ta.CDL3OUTSIDE(dataframe) # values [0, -100, 100]
|
||||||
|
# # Three Inside Up/Down: values [0, -100, 100]
|
||||||
|
# dataframe['CDL3INSIDE'] = ta.CDL3INSIDE(dataframe) # values [0, -100, 100]
|
||||||
|
|
||||||
|
# # Chart type
|
||||||
|
# # ------------------------------------
|
||||||
|
# # Heikin Ashi Strategy
|
||||||
|
# heikinashi = qtpylib.heikinashi(dataframe)
|
||||||
|
# dataframe['ha_open'] = heikinashi['open']
|
||||||
|
# dataframe['ha_close'] = heikinashi['close']
|
||||||
|
# dataframe['ha_high'] = heikinashi['high']
|
||||||
|
# dataframe['ha_low'] = heikinashi['low']
|
||||||
|
|
||||||
|
# Retrieve best bid and best ask from the orderbook
|
||||||
|
# ------------------------------------
|
||||||
|
"""
|
||||||
|
# first check if dataprovider is available
|
||||||
|
if self.dp:
|
||||||
|
if self.dp.runmode in ('live', 'dry_run'):
|
||||||
|
ob = self.dp.orderbook(metadata['pair'], 1)
|
||||||
|
dataframe['best_bid'] = ob['bids'][0][0]
|
||||||
|
dataframe['best_ask'] = ob['asks'][0][0]
|
||||||
|
"""
|
||||||
|
|
||||||
|
return dataframe
|
||||||
|
|
||||||
|
def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||||
|
"""
|
||||||
|
Based on TA indicators, populates the buy signal for the given dataframe
|
||||||
|
:param dataframe: DataFrame populated with indicators
|
||||||
|
:param metadata: Additional information, like the currently traded pair
|
||||||
|
:return: DataFrame with buy column
|
||||||
|
"""
|
||||||
|
dataframe.loc[
|
||||||
|
(
|
||||||
|
(qtpylib.crossed_above(dataframe['rsi'], 30)) & # Signal: RSI crosses above 30
|
||||||
|
(dataframe['tema'] <= dataframe['bb_middleband']) & # Guard: tema below BB middle
|
||||||
|
(dataframe['tema'] > dataframe['tema'].shift(1)) & # Guard: tema is raising
|
||||||
|
(dataframe['volume'] > 0) # Make sure Volume is not 0
|
||||||
|
),
|
||||||
|
'buy'] = 1
|
||||||
|
|
||||||
|
return dataframe
|
||||||
|
|
||||||
|
def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||||
|
"""
|
||||||
|
Based on TA indicators, populates the sell signal for the given dataframe
|
||||||
|
:param dataframe: DataFrame populated with indicators
|
||||||
|
:param metadata: Additional information, like the currently traded pair
|
||||||
|
:return: DataFrame with buy column
|
||||||
|
"""
|
||||||
|
dataframe.loc[
|
||||||
|
(
|
||||||
|
(qtpylib.crossed_above(dataframe['rsi'], 70)) & # Signal: RSI crosses above 70
|
||||||
|
(dataframe['tema'] > dataframe['bb_middleband']) & # Guard: tema above BB middle
|
||||||
|
(dataframe['tema'] < dataframe['tema'].shift(1)) & # Guard: tema is falling
|
||||||
|
(dataframe['volume'] > 0) # Make sure Volume is not 0
|
||||||
|
),
|
||||||
|
'sell'] = 1
|
||||||
|
return dataframe
|
||||||
|
|
364
user_data/strategies/Ressup.py
Normal file
364
user_data/strategies/Ressup.py
Normal file
@ -0,0 +1,364 @@
|
|||||||
|
# pragma pylint: disable=missing-docstring, invalid-name, pointless-string-statement
|
||||||
|
|
||||||
|
# --- Do not remove these libs ---
|
||||||
|
import numpy # noqa
|
||||||
|
import pandas # noqa
|
||||||
|
from pandas import DataFrame
|
||||||
|
|
||||||
|
from freqtrade.strategy.interface import IStrategy
|
||||||
|
|
||||||
|
# --------------------------------
|
||||||
|
# Add your lib to import here
|
||||||
|
import talib.abstract as ta
|
||||||
|
import freqtrade.vendor.qtpylib.indicators as qtpylib
|
||||||
|
|
||||||
|
|
||||||
|
class ResistanceSupport(IStrategy):
|
||||||
|
"""
|
||||||
|
This is a strategy template to get you started.
|
||||||
|
More information in https://github.com/freqtrade/freqtrade/blob/develop/docs/bot-optimization.md
|
||||||
|
|
||||||
|
You can:
|
||||||
|
:return: a Dataframe with all mandatory indicators for the strategies
|
||||||
|
- Rename the class name (Do not forget to update class_name)
|
||||||
|
- Add any methods you want to build your strategy
|
||||||
|
- Add any lib you need to build your strategy
|
||||||
|
|
||||||
|
You must keep:
|
||||||
|
- the lib in the section "Do not remove these libs"
|
||||||
|
- the prototype for the methods: minimal_roi, stoploss, populate_indicators, populate_buy_trend,
|
||||||
|
populate_sell_trend, hyperopt_space, buy_strategy_generator
|
||||||
|
"""
|
||||||
|
# Strategy interface version - allow new iterations of the strategy interface.
|
||||||
|
# Check the documentation or the Sample strategy to get the latest version.
|
||||||
|
INTERFACE_VERSION = 2
|
||||||
|
|
||||||
|
# Minimal ROI designed for the strategy.
|
||||||
|
# This attribute will be overridden if the config file contains "minimal_roi".
|
||||||
|
minimal_roi = {
|
||||||
|
"60": 0.01,
|
||||||
|
"30": 0.02,
|
||||||
|
"0": 0.04
|
||||||
|
}
|
||||||
|
|
||||||
|
# Optimal stoploss designed for the strategy.
|
||||||
|
# This attribute will be overridden if the config file contains "stoploss".
|
||||||
|
stoploss = -0.10
|
||||||
|
|
||||||
|
# Trailing stoploss
|
||||||
|
trailing_stop = False
|
||||||
|
# trailing_only_offset_is_reached = False
|
||||||
|
# trailing_stop_positive = 0.01
|
||||||
|
# trailing_stop_positive_offset = 0.0 # Disabled / not configured
|
||||||
|
|
||||||
|
# Optimal timeframe for the strategy.
|
||||||
|
timeframe = '5m'
|
||||||
|
|
||||||
|
# Run "populate_indicators()" only for new candle.
|
||||||
|
process_only_new_candles = False
|
||||||
|
|
||||||
|
# These values can be overridden in the "ask_strategy" section in the config.
|
||||||
|
use_sell_signal = True
|
||||||
|
sell_profit_only = False
|
||||||
|
ignore_roi_if_buy_signal = False
|
||||||
|
|
||||||
|
# Number of candles the strategy requires before producing valid signals
|
||||||
|
startup_candle_count: int = 20
|
||||||
|
|
||||||
|
# Optional order type mapping.
|
||||||
|
order_types = {
|
||||||
|
'buy': 'limit',
|
||||||
|
'sell': 'limit',
|
||||||
|
'stoploss': 'market',
|
||||||
|
'stoploss_on_exchange': False
|
||||||
|
}
|
||||||
|
|
||||||
|
# Optional order time in force.
|
||||||
|
order_time_in_force = {
|
||||||
|
'buy': 'gtc',
|
||||||
|
'sell': 'gtc'
|
||||||
|
}
|
||||||
|
|
||||||
|
plot_config = {
|
||||||
|
# Main plot indicators (Moving averages, ...)
|
||||||
|
'main_plot': {
|
||||||
|
'tema': {},
|
||||||
|
'sar': {'color': 'white'},
|
||||||
|
},
|
||||||
|
'subplots': {
|
||||||
|
# Subplots - each dict defines one additional plot
|
||||||
|
"MACD": {
|
||||||
|
'macd': {'color': 'blue'},
|
||||||
|
'macdsignal': {'color': 'orange'},
|
||||||
|
},
|
||||||
|
"RSI": {
|
||||||
|
'rsi': {'color': 'red'},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
def informative_pairs(self):
|
||||||
|
"""
|
||||||
|
Define additional, informative pair/interval combinations to be cached from the exchange.
|
||||||
|
These pair/interval combinations are non-tradeable, unless they are part
|
||||||
|
of the whitelist as well.
|
||||||
|
For more information, please consult the documentation
|
||||||
|
:return: List of tuples in the format (pair, interval)
|
||||||
|
Sample: return [("ETH/USDT", "5m"),
|
||||||
|
("BTC/USDT", "15m"),
|
||||||
|
]
|
||||||
|
"""
|
||||||
|
return []
|
||||||
|
|
||||||
|
def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||||
|
"""
|
||||||
|
Adds several different TA indicators to the given DataFrame
|
||||||
|
|
||||||
|
Performance Note: For the best performance be frugal on the number of indicators
|
||||||
|
you are using. Let uncomment only the indicator you are using in your strategies
|
||||||
|
or your hyperopt configuration, otherwise you will waste your memory and CPU usage.
|
||||||
|
:param dataframe: Dataframe with data from the exchange
|
||||||
|
:param metadata: Additional information, like the currently traded pair
|
||||||
|
:return: a Dataframe with all mandatory indicators for the strategies
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Momentum Indicators
|
||||||
|
# ------------------------------------
|
||||||
|
|
||||||
|
# ADX
|
||||||
|
dataframe['adx'] = ta.ADX(dataframe)
|
||||||
|
|
||||||
|
# # Plus Directional Indicator / Movement
|
||||||
|
# dataframe['plus_dm'] = ta.PLUS_DM(dataframe)
|
||||||
|
# dataframe['plus_di'] = ta.PLUS_DI(dataframe)
|
||||||
|
|
||||||
|
# # Minus Directional Indicator / Movement
|
||||||
|
# dataframe['minus_dm'] = ta.MINUS_DM(dataframe)
|
||||||
|
# dataframe['minus_di'] = ta.MINUS_DI(dataframe)
|
||||||
|
|
||||||
|
# # Aroon, Aroon Oscillator
|
||||||
|
# aroon = ta.AROON(dataframe)
|
||||||
|
# dataframe['aroonup'] = aroon['aroonup']
|
||||||
|
# dataframe['aroondown'] = aroon['aroondown']
|
||||||
|
# dataframe['aroonosc'] = ta.AROONOSC(dataframe)
|
||||||
|
|
||||||
|
# # Awesome Oscillator
|
||||||
|
# dataframe['ao'] = qtpylib.awesome_oscillator(dataframe)
|
||||||
|
|
||||||
|
# # Keltner Channel
|
||||||
|
# keltner = qtpylib.keltner_channel(dataframe)
|
||||||
|
# dataframe["kc_upperband"] = keltner["upper"]
|
||||||
|
# dataframe["kc_lowerband"] = keltner["lower"]
|
||||||
|
# dataframe["kc_middleband"] = keltner["mid"]
|
||||||
|
# dataframe["kc_percent"] = (
|
||||||
|
# (dataframe["close"] - dataframe["kc_lowerband"]) /
|
||||||
|
# (dataframe["kc_upperband"] - dataframe["kc_lowerband"])
|
||||||
|
# )
|
||||||
|
# dataframe["kc_width"] = (
|
||||||
|
# (dataframe["kc_upperband"] - dataframe["kc_lowerband"]) / dataframe["kc_middleband"]
|
||||||
|
# )
|
||||||
|
|
||||||
|
# # Ultimate Oscillator
|
||||||
|
# dataframe['uo'] = ta.ULTOSC(dataframe)
|
||||||
|
|
||||||
|
# # Commodity Channel Index: values [Oversold:-100, Overbought:100]
|
||||||
|
# dataframe['cci'] = ta.CCI(dataframe)
|
||||||
|
|
||||||
|
# RSI
|
||||||
|
dataframe['rsi'] = ta.RSI(dataframe)
|
||||||
|
|
||||||
|
# # Inverse Fisher transform on RSI: values [-1.0, 1.0] (https://goo.gl/2JGGoy)
|
||||||
|
# rsi = 0.1 * (dataframe['rsi'] - 50)
|
||||||
|
# dataframe['fisher_rsi'] = (np.exp(2 * rsi) - 1) / (np.exp(2 * rsi) + 1)
|
||||||
|
|
||||||
|
# # Inverse Fisher transform on RSI normalized: values [0.0, 100.0] (https://goo.gl/2JGGoy)
|
||||||
|
# dataframe['fisher_rsi_norma'] = 50 * (dataframe['fisher_rsi'] + 1)
|
||||||
|
|
||||||
|
# # Stochastic Slow
|
||||||
|
# stoch = ta.STOCH(dataframe)
|
||||||
|
# dataframe['slowd'] = stoch['slowd']
|
||||||
|
# dataframe['slowk'] = stoch['slowk']
|
||||||
|
|
||||||
|
# Stochastic Fast
|
||||||
|
stoch_fast = ta.STOCHF(dataframe)
|
||||||
|
dataframe['fastd'] = stoch_fast['fastd']
|
||||||
|
dataframe['fastk'] = stoch_fast['fastk']
|
||||||
|
|
||||||
|
# # Stochastic RSI
|
||||||
|
# stoch_rsi = ta.STOCHRSI(dataframe)
|
||||||
|
# dataframe['fastd_rsi'] = stoch_rsi['fastd']
|
||||||
|
# dataframe['fastk_rsi'] = stoch_rsi['fastk']
|
||||||
|
|
||||||
|
# MACD
|
||||||
|
macd = ta.MACD(dataframe)
|
||||||
|
dataframe['macd'] = macd['macd']
|
||||||
|
dataframe['macdsignal'] = macd['macdsignal']
|
||||||
|
dataframe['macdhist'] = macd['macdhist']
|
||||||
|
|
||||||
|
# MFI
|
||||||
|
dataframe['mfi'] = ta.MFI(dataframe)
|
||||||
|
|
||||||
|
# # ROC
|
||||||
|
# dataframe['roc'] = ta.ROC(dataframe)
|
||||||
|
|
||||||
|
# Overlap Studies
|
||||||
|
# ------------------------------------
|
||||||
|
|
||||||
|
# Bollinger Bands
|
||||||
|
bollinger = qtpylib.bollinger_bands(qtpylib.typical_price(dataframe), window=20, stds=2)
|
||||||
|
dataframe['bb_lowerband'] = bollinger['lower']
|
||||||
|
dataframe['bb_middleband'] = bollinger['mid']
|
||||||
|
dataframe['bb_upperband'] = bollinger['upper']
|
||||||
|
dataframe["bb_percent"] = (
|
||||||
|
(dataframe["close"] - dataframe["bb_lowerband"]) /
|
||||||
|
(dataframe["bb_upperband"] - dataframe["bb_lowerband"])
|
||||||
|
)
|
||||||
|
dataframe["bb_width"] = (
|
||||||
|
(dataframe["bb_upperband"] - dataframe["bb_lowerband"]) / dataframe["bb_middleband"]
|
||||||
|
)
|
||||||
|
|
||||||
|
# Bollinger Bands - Weighted (EMA based instead of SMA)
|
||||||
|
# weighted_bollinger = qtpylib.weighted_bollinger_bands(
|
||||||
|
# qtpylib.typical_price(dataframe), window=20, stds=2
|
||||||
|
# )
|
||||||
|
# dataframe["wbb_upperband"] = weighted_bollinger["upper"]
|
||||||
|
# dataframe["wbb_lowerband"] = weighted_bollinger["lower"]
|
||||||
|
# dataframe["wbb_middleband"] = weighted_bollinger["mid"]
|
||||||
|
# dataframe["wbb_percent"] = (
|
||||||
|
# (dataframe["close"] - dataframe["wbb_lowerband"]) /
|
||||||
|
# (dataframe["wbb_upperband"] - dataframe["wbb_lowerband"])
|
||||||
|
# )
|
||||||
|
# dataframe["wbb_width"] = (
|
||||||
|
# (dataframe["wbb_upperband"] - dataframe["wbb_lowerband"]) / dataframe["wbb_middleband"]
|
||||||
|
# )
|
||||||
|
|
||||||
|
# # EMA - Exponential Moving Average
|
||||||
|
# dataframe['ema3'] = ta.EMA(dataframe, timeperiod=3)
|
||||||
|
# dataframe['ema5'] = ta.EMA(dataframe, timeperiod=5)
|
||||||
|
# dataframe['ema10'] = ta.EMA(dataframe, timeperiod=10)
|
||||||
|
# dataframe['ema21'] = ta.EMA(dataframe, timeperiod=21)
|
||||||
|
# dataframe['ema50'] = ta.EMA(dataframe, timeperiod=50)
|
||||||
|
# dataframe['ema100'] = ta.EMA(dataframe, timeperiod=100)
|
||||||
|
|
||||||
|
# # SMA - Simple Moving Average
|
||||||
|
# dataframe['sma3'] = ta.SMA(dataframe, timeperiod=3)
|
||||||
|
# dataframe['sma5'] = ta.SMA(dataframe, timeperiod=5)
|
||||||
|
# dataframe['sma10'] = ta.SMA(dataframe, timeperiod=10)
|
||||||
|
# dataframe['sma21'] = ta.SMA(dataframe, timeperiod=21)
|
||||||
|
# dataframe['sma50'] = ta.SMA(dataframe, timeperiod=50)
|
||||||
|
# dataframe['sma100'] = ta.SMA(dataframe, timeperiod=100)
|
||||||
|
|
||||||
|
# Parabolic SAR
|
||||||
|
dataframe['sar'] = ta.SAR(dataframe)
|
||||||
|
|
||||||
|
# TEMA - Triple Exponential Moving Average
|
||||||
|
dataframe['tema'] = ta.TEMA(dataframe, timeperiod=9)
|
||||||
|
|
||||||
|
# Cycle Indicator
|
||||||
|
# ------------------------------------
|
||||||
|
# Hilbert Transform Indicator - SineWave
|
||||||
|
hilbert = ta.HT_SINE(dataframe)
|
||||||
|
dataframe['htsine'] = hilbert['sine']
|
||||||
|
dataframe['htleadsine'] = hilbert['leadsine']
|
||||||
|
|
||||||
|
# Pattern Recognition - Bullish candlestick patterns
|
||||||
|
# ------------------------------------
|
||||||
|
# # Hammer: values [0, 100]
|
||||||
|
# dataframe['CDLHAMMER'] = ta.CDLHAMMER(dataframe)
|
||||||
|
# # Inverted Hammer: values [0, 100]
|
||||||
|
# dataframe['CDLINVERTEDHAMMER'] = ta.CDLINVERTEDHAMMER(dataframe)
|
||||||
|
# # Dragonfly Doji: values [0, 100]
|
||||||
|
# dataframe['CDLDRAGONFLYDOJI'] = ta.CDLDRAGONFLYDOJI(dataframe)
|
||||||
|
# # Piercing Line: values [0, 100]
|
||||||
|
# dataframe['CDLPIERCING'] = ta.CDLPIERCING(dataframe) # values [0, 100]
|
||||||
|
# # Morningstar: values [0, 100]
|
||||||
|
# dataframe['CDLMORNINGSTAR'] = ta.CDLMORNINGSTAR(dataframe) # values [0, 100]
|
||||||
|
# # Three White Soldiers: values [0, 100]
|
||||||
|
# dataframe['CDL3WHITESOLDIERS'] = ta.CDL3WHITESOLDIERS(dataframe) # values [0, 100]
|
||||||
|
|
||||||
|
# Pattern Recognition - Bearish candlestick patterns
|
||||||
|
# ------------------------------------
|
||||||
|
# # Hanging Man: values [0, 100]
|
||||||
|
# dataframe['CDLHANGINGMAN'] = ta.CDLHANGINGMAN(dataframe)
|
||||||
|
# # Shooting Star: values [0, 100]
|
||||||
|
# dataframe['CDLSHOOTINGSTAR'] = ta.CDLSHOOTINGSTAR(dataframe)
|
||||||
|
# # Gravestone Doji: values [0, 100]
|
||||||
|
# dataframe['CDLGRAVESTONEDOJI'] = ta.CDLGRAVESTONEDOJI(dataframe)
|
||||||
|
# # Dark Cloud Cover: values [0, 100]
|
||||||
|
# dataframe['CDLDARKCLOUDCOVER'] = ta.CDLDARKCLOUDCOVER(dataframe)
|
||||||
|
# # Evening Doji Star: values [0, 100]
|
||||||
|
# dataframe['CDLEVENINGDOJISTAR'] = ta.CDLEVENINGDOJISTAR(dataframe)
|
||||||
|
# # Evening Star: values [0, 100]
|
||||||
|
# dataframe['CDLEVENINGSTAR'] = ta.CDLEVENINGSTAR(dataframe)
|
||||||
|
|
||||||
|
# Pattern Recognition - Bullish/Bearish candlestick patterns
|
||||||
|
# ------------------------------------
|
||||||
|
# # Three Line Strike: values [0, -100, 100]
|
||||||
|
# dataframe['CDL3LINESTRIKE'] = ta.CDL3LINESTRIKE(dataframe)
|
||||||
|
# # Spinning Top: values [0, -100, 100]
|
||||||
|
# dataframe['CDLSPINNINGTOP'] = ta.CDLSPINNINGTOP(dataframe) # values [0, -100, 100]
|
||||||
|
# # Engulfing: values [0, -100, 100]
|
||||||
|
# dataframe['CDLENGULFING'] = ta.CDLENGULFING(dataframe) # values [0, -100, 100]
|
||||||
|
# # Harami: values [0, -100, 100]
|
||||||
|
# dataframe['CDLHARAMI'] = ta.CDLHARAMI(dataframe) # values [0, -100, 100]
|
||||||
|
# # Three Outside Up/Down: values [0, -100, 100]
|
||||||
|
# dataframe['CDL3OUTSIDE'] = ta.CDL3OUTSIDE(dataframe) # values [0, -100, 100]
|
||||||
|
# # Three Inside Up/Down: values [0, -100, 100]
|
||||||
|
# dataframe['CDL3INSIDE'] = ta.CDL3INSIDE(dataframe) # values [0, -100, 100]
|
||||||
|
|
||||||
|
# # Chart type
|
||||||
|
# # ------------------------------------
|
||||||
|
# # Heikin Ashi Strategy
|
||||||
|
# heikinashi = qtpylib.heikinashi(dataframe)
|
||||||
|
# dataframe['ha_open'] = heikinashi['open']
|
||||||
|
# dataframe['ha_close'] = heikinashi['close']
|
||||||
|
# dataframe['ha_high'] = heikinashi['high']
|
||||||
|
# dataframe['ha_low'] = heikinashi['low']
|
||||||
|
|
||||||
|
# Retrieve best bid and best ask from the orderbook
|
||||||
|
# ------------------------------------
|
||||||
|
"""
|
||||||
|
# first check if dataprovider is available
|
||||||
|
if self.dp:
|
||||||
|
if self.dp.runmode in ('live', 'dry_run'):
|
||||||
|
ob = self.dp.orderbook(metadata['pair'], 1)
|
||||||
|
dataframe['best_bid'] = ob['bids'][0][0]
|
||||||
|
dataframe['best_ask'] = ob['asks'][0][0]
|
||||||
|
"""
|
||||||
|
|
||||||
|
return dataframe
|
||||||
|
|
||||||
|
def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||||
|
"""
|
||||||
|
Based on TA indicators, populates the buy signal for the given dataframe
|
||||||
|
:param dataframe: DataFrame populated with indicators
|
||||||
|
:param metadata: Additional information, like the currently traded pair
|
||||||
|
:return: DataFrame with buy column
|
||||||
|
"""
|
||||||
|
dataframe.loc[
|
||||||
|
(
|
||||||
|
(qtpylib.crossed_above(dataframe['rsi'], 30)) & # Signal: RSI crosses above 30
|
||||||
|
(dataframe['tema'] <= dataframe['bb_middleband']) & # Guard: tema below BB middle
|
||||||
|
(dataframe['tema'] > dataframe['tema'].shift(1)) & # Guard: tema is raising
|
||||||
|
(dataframe['volume'] > 0) # Make sure Volume is not 0
|
||||||
|
),
|
||||||
|
'buy'] = 1
|
||||||
|
|
||||||
|
return dataframe
|
||||||
|
|
||||||
|
def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||||
|
"""
|
||||||
|
Based on TA indicators, populates the sell signal for the given dataframe
|
||||||
|
:param dataframe: DataFrame populated with indicators
|
||||||
|
:param metadata: Additional information, like the currently traded pair
|
||||||
|
:return: DataFrame with buy column
|
||||||
|
"""
|
||||||
|
dataframe.loc[
|
||||||
|
(
|
||||||
|
(qtpylib.crossed_above(dataframe['rsi'], 70)) & # Signal: RSI crosses above 70
|
||||||
|
(dataframe['tema'] > dataframe['bb_middleband']) & # Guard: tema above BB middle
|
||||||
|
(dataframe['tema'] < dataframe['tema'].shift(1)) & # Guard: tema is falling
|
||||||
|
(dataframe['volume'] > 0) # Make sure Volume is not 0
|
||||||
|
),
|
||||||
|
'sell'] = 1
|
||||||
|
return dataframe
|
||||||
|
|
133
user_data/strategies/bbrsi.py
Normal file
133
user_data/strategies/bbrsi.py
Normal file
@ -0,0 +1,133 @@
|
|||||||
|
# pragma pylint: disable=missing-docstring, invalid-name, pointless-string-statement
|
||||||
|
|
||||||
|
# --- Do not remove these libs ---
|
||||||
|
import numpy # noqa
|
||||||
|
import pandas # noqa
|
||||||
|
from pandas import DataFrame
|
||||||
|
|
||||||
|
from freqtrade.strategy.interface import IStrategy
|
||||||
|
|
||||||
|
# --------------------------------
|
||||||
|
# Add your lib to import here
|
||||||
|
import talib.abstract as ta
|
||||||
|
import freqtrade.vendor.qtpylib.indicators as qtpylib
|
||||||
|
|
||||||
|
|
||||||
|
class BBRSI(IStrategy):
|
||||||
|
"""
|
||||||
|
You must keep:
|
||||||
|
- the lib in the section "Do not remove these libs"
|
||||||
|
- the prototype for the methods: minimal_roi, stoploss, populate_indicators, populate_buy_trend,
|
||||||
|
populate_sell_trend, hyperopt_space, buy_strategy_generator
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Strategy interface version - allow new iterations of the strategy interface.
|
||||||
|
INTERFACE_VERSION = 2
|
||||||
|
|
||||||
|
# Minimal ROI designed for the strategy.
|
||||||
|
# Will override config file.
|
||||||
|
minimal_roi = {
|
||||||
|
"0": 100
|
||||||
|
}
|
||||||
|
|
||||||
|
# Optimal stoploss designed for the strategy.
|
||||||
|
# Will override config file.
|
||||||
|
stoploss = -0.99
|
||||||
|
|
||||||
|
# Trailing stoploss
|
||||||
|
trailing_stop = False
|
||||||
|
# trailing_only_offset_is_reached = False
|
||||||
|
# trailing_stop_positive = 0.01
|
||||||
|
# trailing_stop_positive_offset = 0.0 # Disabled / not configured
|
||||||
|
|
||||||
|
# Optimal timeframe for the strategy.
|
||||||
|
timeframe = '1h'
|
||||||
|
|
||||||
|
# Run "populate_indicators()" only for new candle.
|
||||||
|
process_only_new_candles = False
|
||||||
|
|
||||||
|
# These values can be overridden in the "ask_strategy" section in the config.
|
||||||
|
use_sell_signal = True
|
||||||
|
sell_profit_only = False
|
||||||
|
ignore_roi_if_buy_signal = False
|
||||||
|
|
||||||
|
# Number of candles the strategy requires before producing valid signals
|
||||||
|
startup_candle_count: int = 20
|
||||||
|
|
||||||
|
# Optional order type mapping.
|
||||||
|
order_types = {
|
||||||
|
'buy': 'limit',
|
||||||
|
'sell': 'limit',
|
||||||
|
'stoploss': 'market',
|
||||||
|
'stoploss_on_exchange': False
|
||||||
|
}
|
||||||
|
|
||||||
|
# Optional order time in force.
|
||||||
|
order_time_in_force = {
|
||||||
|
'buy': 'gtc',
|
||||||
|
'sell': 'gtc'
|
||||||
|
}
|
||||||
|
|
||||||
|
plot_config = {
|
||||||
|
# Main plot indicators (Moving averages, ...)
|
||||||
|
'main_plot': {
|
||||||
|
'tema': {},
|
||||||
|
'sar': {'color': 'white'},
|
||||||
|
},
|
||||||
|
'subplots': {
|
||||||
|
# Subplots - each dict defines one additional plot
|
||||||
|
"MACD": {
|
||||||
|
'macd': {'color': 'blue'},
|
||||||
|
'macdsignal': {'color': 'orange'},
|
||||||
|
},
|
||||||
|
"RSI": {
|
||||||
|
'rsi': {'color': 'red'},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def informative_pairs(self):
|
||||||
|
"""
|
||||||
|
Define additional, informative pair/interval combinations to be cached from the exchange.
|
||||||
|
These pair/interval combinations are non-tradeable, unless they are part
|
||||||
|
of the whitelist as well.
|
||||||
|
For more information, please consult the documentation
|
||||||
|
:return: List of tuples in the format (pair, interval)
|
||||||
|
Sample: return [("ETH/USDT", "5m"),
|
||||||
|
("BTC/USDT", "15m"),
|
||||||
|
]
|
||||||
|
"""
|
||||||
|
return []
|
||||||
|
|
||||||
|
def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||||
|
|
||||||
|
# RSI
|
||||||
|
dataframe['rsi'] = ta.RSI(dataframe)
|
||||||
|
|
||||||
|
# Bollinger Bands
|
||||||
|
bollinger = qtpylib.bollinger_bands(qtpylib.typical_price(dataframe), window=20, stds=2)
|
||||||
|
dataframe['bb_lowerband'] = bollinger['lower']
|
||||||
|
dataframe['bb_middleband'] = bollinger['mid']
|
||||||
|
dataframe['bb_upperband'] = bollinger['upper']
|
||||||
|
|
||||||
|
return dataframe
|
||||||
|
|
||||||
|
def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||||
|
|
||||||
|
dataframe.loc[
|
||||||
|
(
|
||||||
|
(dataframe['rsi'] > 30) & # RSI above 30
|
||||||
|
(dataframe['close'] < dataframe['bb_lowerband']) # close price under low bb
|
||||||
|
),
|
||||||
|
'buy'] = 1
|
||||||
|
|
||||||
|
return dataframe
|
||||||
|
|
||||||
|
def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||||
|
|
||||||
|
dataframe.loc[
|
||||||
|
(
|
||||||
|
(dataframe['close'] > dataframe['bb_middleband']) # close price above the middle bb
|
||||||
|
),
|
||||||
|
'sell'] = 1
|
||||||
|
return dataframe
|
120
user_data/strategies/examplefreqtrade1.py
Normal file
120
user_data/strategies/examplefreqtrade1.py
Normal file
@ -0,0 +1,120 @@
|
|||||||
|
# --- Do not remove these libs ---
|
||||||
|
from freqtrade.strategy.interface import IStrategy
|
||||||
|
from typing import Dict, List
|
||||||
|
from functools import reduce
|
||||||
|
from pandas import DataFrame
|
||||||
|
# --------------------------------
|
||||||
|
|
||||||
|
import talib.abstract as ta
|
||||||
|
import freqtrade.vendor.qtpylib.indicators as qtpylib
|
||||||
|
|
||||||
|
|
||||||
|
class Examplestrategy1(IStrategy):
|
||||||
|
"""
|
||||||
|
Strategy 001
|
||||||
|
author@: Gerald Lonlas
|
||||||
|
github@: https://github.com/freqtrade/freqtrade-strategies
|
||||||
|
|
||||||
|
How to use it?
|
||||||
|
> python3 ./freqtrade/main.py -s Strategy001
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Minimal ROI designed for the strategy.
|
||||||
|
# This attribute will be overridden if the config file contains "minimal_roi"
|
||||||
|
minimal_roi = {
|
||||||
|
"60": 0.01,
|
||||||
|
"30": 0.03,
|
||||||
|
"20": 0.04,
|
||||||
|
"0": 0.05
|
||||||
|
}
|
||||||
|
|
||||||
|
# Optimal stoploss designed for the strategy
|
||||||
|
# This attribute will be overridden if the config file contains "stoploss"
|
||||||
|
stoploss = -0.10
|
||||||
|
|
||||||
|
# Optimal ticker interval for the strategy
|
||||||
|
ticker_interval = '5m'
|
||||||
|
|
||||||
|
# trailing stoploss
|
||||||
|
trailing_stop = False
|
||||||
|
trailing_stop_positive = 0.01
|
||||||
|
trailing_stop_positive_offset = 0.02
|
||||||
|
|
||||||
|
# run "populate_indicators" only for new candle
|
||||||
|
process_only_new_candles = False
|
||||||
|
|
||||||
|
# Experimental settings (configuration will overide these if set)
|
||||||
|
use_sell_signal = True
|
||||||
|
sell_profit_only = True
|
||||||
|
ignore_roi_if_buy_signal = False
|
||||||
|
|
||||||
|
# Optional order type mapping
|
||||||
|
order_types = {
|
||||||
|
'buy': 'limit',
|
||||||
|
'sell': 'limit',
|
||||||
|
'stoploss': 'market',
|
||||||
|
'stoploss_on_exchange': False
|
||||||
|
}
|
||||||
|
|
||||||
|
def informative_pairs(self):
|
||||||
|
"""
|
||||||
|
Define additional, informative pair/interval combinations to be cached from the exchange.
|
||||||
|
These pair/interval combinations are non-tradeable, unless they are part
|
||||||
|
of the whitelist as well.
|
||||||
|
For more information, please consult the documentation
|
||||||
|
:return: List of tuples in the format (pair, interval)
|
||||||
|
Sample: return [("ETH/USDT", "5m"),
|
||||||
|
("BTC/USDT", "15m"),
|
||||||
|
]
|
||||||
|
"""
|
||||||
|
return []
|
||||||
|
|
||||||
|
def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||||
|
"""
|
||||||
|
Adds several different TA indicators to the given DataFrame
|
||||||
|
|
||||||
|
Performance Note: For the best performance be frugal on the number of indicators
|
||||||
|
you are using. Let uncomment only the indicator you are using in your strategies
|
||||||
|
or your hyperopt configuration, otherwise you will waste your memory and CPU usage.
|
||||||
|
"""
|
||||||
|
|
||||||
|
dataframe['ema20'] = ta.EMA(dataframe, timeperiod=20)
|
||||||
|
dataframe['ema50'] = ta.EMA(dataframe, timeperiod=50)
|
||||||
|
dataframe['ema100'] = ta.EMA(dataframe, timeperiod=100)
|
||||||
|
|
||||||
|
heikinashi = qtpylib.heikinashi(dataframe)
|
||||||
|
dataframe['ha_open'] = heikinashi['open']
|
||||||
|
dataframe['ha_close'] = heikinashi['close']
|
||||||
|
|
||||||
|
return dataframe
|
||||||
|
|
||||||
|
def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||||
|
"""
|
||||||
|
Based on TA indicators, populates the buy signal for the given dataframe
|
||||||
|
:param dataframe: DataFrame
|
||||||
|
:return: DataFrame with buy column
|
||||||
|
"""
|
||||||
|
dataframe.loc[
|
||||||
|
(
|
||||||
|
qtpylib.crossed_above(dataframe['ema20'], dataframe['ema50']) &
|
||||||
|
(dataframe['ha_close'] > dataframe['ema20']) &
|
||||||
|
(dataframe['ha_open'] < dataframe['ha_close']) # green bar
|
||||||
|
),
|
||||||
|
'buy'] = 1
|
||||||
|
|
||||||
|
return dataframe
|
||||||
|
|
||||||
|
def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||||
|
"""
|
||||||
|
Based on TA indicators, populates the sell signal for the given dataframe
|
||||||
|
:param dataframe: DataFrame
|
||||||
|
:return: DataFrame with buy column
|
||||||
|
"""
|
||||||
|
dataframe.loc[
|
||||||
|
(
|
||||||
|
qtpylib.crossed_above(dataframe['ema50'], dataframe['ema100']) &
|
||||||
|
(dataframe['ha_close'] < dataframe['ema20']) &
|
||||||
|
(dataframe['ha_open'] > dataframe['ha_close']) # red bar
|
||||||
|
),
|
||||||
|
'sell'] = 1
|
||||||
|
return dataframe
|
132
user_data/strategies/examplefreqtrade2.py
Normal file
132
user_data/strategies/examplefreqtrade2.py
Normal file
@ -0,0 +1,132 @@
|
|||||||
|
|
||||||
|
# --- Do not remove these libs ---
|
||||||
|
from freqtrade.strategy.interface import IStrategy
|
||||||
|
from typing import Dict, List
|
||||||
|
from functools import reduce
|
||||||
|
from pandas import DataFrame
|
||||||
|
# --------------------------------
|
||||||
|
|
||||||
|
import talib.abstract as ta
|
||||||
|
import freqtrade.vendor.qtpylib.indicators as qtpylib
|
||||||
|
import numpy # noqa
|
||||||
|
|
||||||
|
class Examplestrategy2(IStrategy):
|
||||||
|
"""
|
||||||
|
Strategy 002
|
||||||
|
author@: Gerald Lonlas
|
||||||
|
github@: https://github.com/freqtrade/freqtrade-strategies
|
||||||
|
How to use it?
|
||||||
|
> python3 ./freqtrade/main.py -s Strategy002
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Minimal ROI designed for the strategy.
|
||||||
|
# This attribute will be overridden if the config file contains "minimal_roi"
|
||||||
|
minimal_roi = {
|
||||||
|
"60": 0.01,
|
||||||
|
"30": 0.03,
|
||||||
|
"20": 0.04,
|
||||||
|
"0": 0.05
|
||||||
|
}
|
||||||
|
|
||||||
|
# Optimal stoploss designed for the strategy
|
||||||
|
# This attribute will be overridden if the config file contains "stoploss"
|
||||||
|
stoploss = -0.10
|
||||||
|
|
||||||
|
# Optimal ticker interval for the strategy
|
||||||
|
ticker_interval = '5m'
|
||||||
|
|
||||||
|
# trailing stoploss
|
||||||
|
trailing_stop = False
|
||||||
|
trailing_stop_positive = 0.01
|
||||||
|
trailing_stop_positive_offset = 0.02
|
||||||
|
|
||||||
|
# run "populate_indicators" only for new candle
|
||||||
|
process_only_new_candles = False
|
||||||
|
|
||||||
|
# Experimental settings (configuration will overide these if set)
|
||||||
|
use_sell_signal = True
|
||||||
|
sell_profit_only = True
|
||||||
|
ignore_roi_if_buy_signal = False
|
||||||
|
|
||||||
|
# Optional order type mapping
|
||||||
|
order_types = {
|
||||||
|
'buy': 'limit',
|
||||||
|
'sell': 'limit',
|
||||||
|
'stoploss': 'market',
|
||||||
|
'stoploss_on_exchange': False
|
||||||
|
}
|
||||||
|
|
||||||
|
def informative_pairs(self):
|
||||||
|
"""
|
||||||
|
Define additional, informative pair/interval combinations to be cached from the exchange.
|
||||||
|
These pair/interval combinations are non-tradeable, unless they are part
|
||||||
|
of the whitelist as well.
|
||||||
|
For more information, please consult the documentation
|
||||||
|
:return: List of tuples in the format (pair, interval)
|
||||||
|
Sample: return [("ETH/USDT", "5m"),
|
||||||
|
("BTC/USDT", "15m"),
|
||||||
|
]
|
||||||
|
"""
|
||||||
|
return []
|
||||||
|
|
||||||
|
def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||||
|
"""
|
||||||
|
Adds several different TA indicators to the given DataFrame
|
||||||
|
Performance Note: For the best performance be frugal on the number of indicators
|
||||||
|
you are using. Let uncomment only the indicator you are using in your strategies
|
||||||
|
or your hyperopt configuration, otherwise you will waste your memory and CPU usage.
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Stoch
|
||||||
|
stoch = ta.STOCH(dataframe)
|
||||||
|
dataframe['slowk'] = stoch['slowk']
|
||||||
|
|
||||||
|
# RSI
|
||||||
|
dataframe['rsi'] = ta.RSI(dataframe)
|
||||||
|
|
||||||
|
# Inverse Fisher transform on RSI, values [-1.0, 1.0] (https://goo.gl/2JGGoy)
|
||||||
|
rsi = 0.1 * (dataframe['rsi'] - 50)
|
||||||
|
dataframe['fisher_rsi'] = (numpy.exp(2 * rsi) - 1) / (numpy.exp(2 * rsi) + 1)
|
||||||
|
|
||||||
|
# Bollinger bands
|
||||||
|
bollinger = qtpylib.bollinger_bands(qtpylib.typical_price(dataframe), window=20, stds=2)
|
||||||
|
dataframe['bb_lowerband'] = bollinger['lower']
|
||||||
|
|
||||||
|
# SAR Parabol
|
||||||
|
dataframe['sar'] = ta.SAR(dataframe)
|
||||||
|
|
||||||
|
# Hammer: values [0, 100]
|
||||||
|
dataframe['CDLHAMMER'] = ta.CDLHAMMER(dataframe)
|
||||||
|
|
||||||
|
return dataframe
|
||||||
|
|
||||||
|
def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||||
|
"""
|
||||||
|
Based on TA indicators, populates the buy signal for the given dataframe
|
||||||
|
:param dataframe: DataFrame
|
||||||
|
:return: DataFrame with buy column
|
||||||
|
"""
|
||||||
|
dataframe.loc[
|
||||||
|
(
|
||||||
|
(dataframe['rsi'] < 30) &
|
||||||
|
(dataframe['slowk'] < 20) &
|
||||||
|
(dataframe['bb_lowerband'] > dataframe['close']) &
|
||||||
|
(dataframe['CDLHAMMER'] == 100)
|
||||||
|
),
|
||||||
|
'buy'] = 1
|
||||||
|
|
||||||
|
return dataframe
|
||||||
|
|
||||||
|
def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||||
|
"""
|
||||||
|
Based on TA indicators, populates the sell signal for the given dataframe
|
||||||
|
:param dataframe: DataFrame
|
||||||
|
:return: DataFrame with buy column
|
||||||
|
"""
|
||||||
|
dataframe.loc[
|
||||||
|
(
|
||||||
|
(dataframe['sar'] > dataframe['close']) &
|
||||||
|
(dataframe['fisher_rsi'] > 0.3)
|
||||||
|
),
|
||||||
|
'sell'] = 1
|
||||||
|
return dataframe
|
150
user_data/strategies/examplefreqtrade3.py
Normal file
150
user_data/strategies/examplefreqtrade3.py
Normal file
@ -0,0 +1,150 @@
|
|||||||
|
|
||||||
|
# --- Do not remove these libs ---
|
||||||
|
from freqtrade.strategy.interface import IStrategy
|
||||||
|
from typing import Dict, List
|
||||||
|
from functools import reduce
|
||||||
|
from pandas import DataFrame
|
||||||
|
# --------------------------------
|
||||||
|
|
||||||
|
import talib.abstract as ta
|
||||||
|
import freqtrade.vendor.qtpylib.indicators as qtpylib
|
||||||
|
import numpy # noqa
|
||||||
|
|
||||||
|
|
||||||
|
class Examplestrategy3(IStrategy):
|
||||||
|
"""
|
||||||
|
Strategy 003
|
||||||
|
author@: Gerald Lonlas
|
||||||
|
github@: https://github.com/freqtrade/freqtrade-strategies
|
||||||
|
How to use it?
|
||||||
|
> python3 ./freqtrade/main.py -s Strategy003
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Minimal ROI designed for the strategy.
|
||||||
|
# This attribute will be overridden if the config file contains "minimal_roi"
|
||||||
|
minimal_roi = {
|
||||||
|
"60": 0.01,
|
||||||
|
"30": 0.03,
|
||||||
|
"20": 0.04,
|
||||||
|
"0": 0.05
|
||||||
|
}
|
||||||
|
|
||||||
|
# Optimal stoploss designed for the strategy
|
||||||
|
# This attribute will be overridden if the config file contains "stoploss"
|
||||||
|
stoploss = -0.10
|
||||||
|
|
||||||
|
# Optimal ticker interval for the strategy
|
||||||
|
ticker_interval = '5m'
|
||||||
|
|
||||||
|
# trailing stoploss
|
||||||
|
trailing_stop = False
|
||||||
|
trailing_stop_positive = 0.01
|
||||||
|
trailing_stop_positive_offset = 0.02
|
||||||
|
|
||||||
|
# run "populate_indicators" only for new candle
|
||||||
|
process_only_new_candles = False
|
||||||
|
|
||||||
|
# Experimental settings (configuration will overide these if set)
|
||||||
|
use_sell_signal = True
|
||||||
|
sell_profit_only = True
|
||||||
|
ignore_roi_if_buy_signal = False
|
||||||
|
|
||||||
|
# Optional order type mapping
|
||||||
|
order_types = {
|
||||||
|
'buy': 'limit',
|
||||||
|
'sell': 'limit',
|
||||||
|
'stoploss': 'market',
|
||||||
|
'stoploss_on_exchange': False
|
||||||
|
}
|
||||||
|
|
||||||
|
def informative_pairs(self):
|
||||||
|
"""
|
||||||
|
Define additional, informative pair/interval combinations to be cached from the exchange.
|
||||||
|
These pair/interval combinations are non-tradeable, unless they are part
|
||||||
|
of the whitelist as well.
|
||||||
|
For more information, please consult the documentation
|
||||||
|
:return: List of tuples in the format (pair, interval)
|
||||||
|
Sample: return [("ETH/USDT", "5m"),
|
||||||
|
("BTC/USDT", "15m"),
|
||||||
|
]
|
||||||
|
"""
|
||||||
|
return []
|
||||||
|
|
||||||
|
def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||||
|
"""
|
||||||
|
Adds several different TA indicators to the given DataFrame
|
||||||
|
Performance Note: For the best performance be frugal on the number of indicators
|
||||||
|
you are using. Let uncomment only the indicator you are using in your strategies
|
||||||
|
or your hyperopt configuration, otherwise you will waste your memory and CPU usage.
|
||||||
|
"""
|
||||||
|
|
||||||
|
# MFI
|
||||||
|
dataframe['mfi'] = ta.MFI(dataframe)
|
||||||
|
|
||||||
|
# Stoch fast
|
||||||
|
stoch_fast = ta.STOCHF(dataframe)
|
||||||
|
dataframe['fastd'] = stoch_fast['fastd']
|
||||||
|
dataframe['fastk'] = stoch_fast['fastk']
|
||||||
|
|
||||||
|
# RSI
|
||||||
|
dataframe['rsi'] = ta.RSI(dataframe)
|
||||||
|
|
||||||
|
# Inverse Fisher transform on RSI, values [-1.0, 1.0] (https://goo.gl/2JGGoy)
|
||||||
|
rsi = 0.1 * (dataframe['rsi'] - 50)
|
||||||
|
dataframe['fisher_rsi'] = (numpy.exp(2 * rsi) - 1) / (numpy.exp(2 * rsi) + 1)
|
||||||
|
|
||||||
|
# Bollinger bands
|
||||||
|
bollinger = qtpylib.bollinger_bands(qtpylib.typical_price(dataframe), window=20, stds=2)
|
||||||
|
dataframe['bb_lowerband'] = bollinger['lower']
|
||||||
|
|
||||||
|
# EMA - Exponential Moving Average
|
||||||
|
dataframe['ema5'] = ta.EMA(dataframe, timeperiod=5)
|
||||||
|
dataframe['ema10'] = ta.EMA(dataframe, timeperiod=10)
|
||||||
|
dataframe['ema50'] = ta.EMA(dataframe, timeperiod=50)
|
||||||
|
dataframe['ema100'] = ta.EMA(dataframe, timeperiod=100)
|
||||||
|
|
||||||
|
# SAR Parabol
|
||||||
|
dataframe['sar'] = ta.SAR(dataframe)
|
||||||
|
|
||||||
|
# SMA - Simple Moving Average
|
||||||
|
dataframe['sma'] = ta.SMA(dataframe, timeperiod=40)
|
||||||
|
|
||||||
|
return dataframe
|
||||||
|
|
||||||
|
def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||||
|
"""
|
||||||
|
Based on TA indicators, populates the buy signal for the given dataframe
|
||||||
|
:param dataframe: DataFrame
|
||||||
|
:return: DataFrame with buy column
|
||||||
|
"""
|
||||||
|
dataframe.loc[
|
||||||
|
(
|
||||||
|
(dataframe['rsi'] < 28) &
|
||||||
|
(dataframe['rsi'] > 0) &
|
||||||
|
(dataframe['close'] < dataframe['sma']) &
|
||||||
|
(dataframe['fisher_rsi'] < -0.94) &
|
||||||
|
(dataframe['mfi'] < 16.0) &
|
||||||
|
(
|
||||||
|
(dataframe['ema50'] > dataframe['ema100']) |
|
||||||
|
(qtpylib.crossed_above(dataframe['ema5'], dataframe['ema10']))
|
||||||
|
) &
|
||||||
|
(dataframe['fastd'] > dataframe['fastk']) &
|
||||||
|
(dataframe['fastd'] > 0)
|
||||||
|
),
|
||||||
|
'buy'] = 1
|
||||||
|
|
||||||
|
return dataframe
|
||||||
|
|
||||||
|
def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||||
|
"""
|
||||||
|
Based on TA indicators, populates the sell signal for the given dataframe
|
||||||
|
:param dataframe: DataFrame
|
||||||
|
:return: DataFrame with buy column
|
||||||
|
"""
|
||||||
|
dataframe.loc[
|
||||||
|
(
|
||||||
|
(dataframe['sar'] > dataframe['close']) &
|
||||||
|
(dataframe['fisher_rsi'] > 0.3)
|
||||||
|
),
|
||||||
|
'sell'] = 1
|
||||||
|
return dataframe
|
152
user_data/strategies/examplefreqtrade4.py
Normal file
152
user_data/strategies/examplefreqtrade4.py
Normal file
@ -0,0 +1,152 @@
|
|||||||
|
|
||||||
|
# --- Do not remove these libs ---
|
||||||
|
from freqtrade.strategy.interface import IStrategy
|
||||||
|
from typing import Dict, List
|
||||||
|
from functools import reduce
|
||||||
|
from pandas import DataFrame
|
||||||
|
# --------------------------------
|
||||||
|
|
||||||
|
import talib.abstract as ta
|
||||||
|
|
||||||
|
|
||||||
|
class Examplestrategy4(IStrategy):
|
||||||
|
|
||||||
|
"""
|
||||||
|
Strategy 004
|
||||||
|
author@: Gerald Lonlas
|
||||||
|
github@: https://github.com/freqtrade/freqtrade-strategies
|
||||||
|
How to use it?
|
||||||
|
> python3 ./freqtrade/main.py -s Strategy004
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Minimal ROI designed for the strategy.
|
||||||
|
# This attribute will be overridden if the config file contains "minimal_roi"
|
||||||
|
minimal_roi = {
|
||||||
|
"60": 0.01,
|
||||||
|
"30": 0.03,
|
||||||
|
"20": 0.04,
|
||||||
|
"0": 0.05
|
||||||
|
}
|
||||||
|
|
||||||
|
# Optimal stoploss designed for the strategy
|
||||||
|
# This attribute will be overridden if the config file contains "stoploss"
|
||||||
|
stoploss = -0.10
|
||||||
|
|
||||||
|
# Optimal ticker interval for the strategy
|
||||||
|
ticker_interval = '5m'
|
||||||
|
|
||||||
|
# trailing stoploss
|
||||||
|
trailing_stop = False
|
||||||
|
trailing_stop_positive = 0.01
|
||||||
|
trailing_stop_positive_offset = 0.02
|
||||||
|
|
||||||
|
# run "populate_indicators" only for new candle
|
||||||
|
process_only_new_candles = False
|
||||||
|
|
||||||
|
# Experimental settings (configuration will overide these if set)
|
||||||
|
use_sell_signal = True
|
||||||
|
sell_profit_only = True
|
||||||
|
ignore_roi_if_buy_signal = False
|
||||||
|
|
||||||
|
# Optional order type mapping
|
||||||
|
order_types = {
|
||||||
|
'buy': 'limit',
|
||||||
|
'sell': 'limit',
|
||||||
|
'stoploss': 'market',
|
||||||
|
'stoploss_on_exchange': False
|
||||||
|
}
|
||||||
|
|
||||||
|
def informative_pairs(self):
|
||||||
|
"""
|
||||||
|
Define additional, informative pair/interval combinations to be cached from the exchange.
|
||||||
|
These pair/interval combinations are non-tradeable, unless they are part
|
||||||
|
of the whitelist as well.
|
||||||
|
For more information, please consult the documentation
|
||||||
|
:return: List of tuples in the format (pair, interval)
|
||||||
|
Sample: return [("ETH/USDT", "5m"),
|
||||||
|
("BTC/USDT", "15m"),
|
||||||
|
]
|
||||||
|
"""
|
||||||
|
return []
|
||||||
|
|
||||||
|
def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||||
|
"""
|
||||||
|
Adds several different TA indicators to the given DataFrame
|
||||||
|
Performance Note: For the best performance be frugal on the number of indicators
|
||||||
|
you are using. Let uncomment only the indicator you are using in your strategies
|
||||||
|
or your hyperopt configuration, otherwise you will waste your memory and CPU usage.
|
||||||
|
"""
|
||||||
|
|
||||||
|
# ADX
|
||||||
|
dataframe['adx'] = ta.ADX(dataframe)
|
||||||
|
dataframe['slowadx'] = ta.ADX(dataframe, 35)
|
||||||
|
|
||||||
|
# Commodity Channel Index: values Oversold:<-100, Overbought:>100
|
||||||
|
dataframe['cci'] = ta.CCI(dataframe)
|
||||||
|
|
||||||
|
# Stoch
|
||||||
|
stoch = ta.STOCHF(dataframe, 5)
|
||||||
|
dataframe['fastd'] = stoch['fastd']
|
||||||
|
dataframe['fastk'] = stoch['fastk']
|
||||||
|
dataframe['fastk-previous'] = dataframe.fastk.shift(1)
|
||||||
|
dataframe['fastd-previous'] = dataframe.fastd.shift(1)
|
||||||
|
|
||||||
|
# Slow Stoch
|
||||||
|
slowstoch = ta.STOCHF(dataframe, 50)
|
||||||
|
dataframe['slowfastd'] = slowstoch['fastd']
|
||||||
|
dataframe['slowfastk'] = slowstoch['fastk']
|
||||||
|
dataframe['slowfastk-previous'] = dataframe.slowfastk.shift(1)
|
||||||
|
dataframe['slowfastd-previous'] = dataframe.slowfastd.shift(1)
|
||||||
|
|
||||||
|
# EMA - Exponential Moving Average
|
||||||
|
dataframe['ema5'] = ta.EMA(dataframe, timeperiod=5)
|
||||||
|
|
||||||
|
dataframe['mean-volume'] = dataframe['volume'].mean()
|
||||||
|
|
||||||
|
return dataframe
|
||||||
|
|
||||||
|
def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||||
|
"""
|
||||||
|
Based on TA indicators, populates the buy signal for the given dataframe
|
||||||
|
:param dataframe: DataFrame
|
||||||
|
:return: DataFrame with buy column
|
||||||
|
"""
|
||||||
|
dataframe.loc[
|
||||||
|
(
|
||||||
|
(
|
||||||
|
(dataframe['adx'] > 50) |
|
||||||
|
(dataframe['slowadx'] > 26)
|
||||||
|
) &
|
||||||
|
(dataframe['cci'] < -100) &
|
||||||
|
(
|
||||||
|
(dataframe['fastk-previous'] < 20) &
|
||||||
|
(dataframe['fastd-previous'] < 20)
|
||||||
|
) &
|
||||||
|
(
|
||||||
|
(dataframe['slowfastk-previous'] < 30) &
|
||||||
|
(dataframe['slowfastd-previous'] < 30)
|
||||||
|
) &
|
||||||
|
(dataframe['fastk-previous'] < dataframe['fastd-previous']) &
|
||||||
|
(dataframe['fastk'] > dataframe['fastd']) &
|
||||||
|
(dataframe['mean-volume'] > 0.75) &
|
||||||
|
(dataframe['close'] > 0.00000100)
|
||||||
|
),
|
||||||
|
'buy'] = 1
|
||||||
|
|
||||||
|
return dataframe
|
||||||
|
|
||||||
|
def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||||
|
"""
|
||||||
|
Based on TA indicators, populates the sell signal for the given dataframe
|
||||||
|
:param dataframe: DataFrame
|
||||||
|
:return: DataFrame with buy column
|
||||||
|
"""
|
||||||
|
dataframe.loc[
|
||||||
|
(
|
||||||
|
(dataframe['slowadx'] < 25) &
|
||||||
|
((dataframe['fastk'] > 70) | (dataframe['fastd'] > 70)) &
|
||||||
|
(dataframe['fastk-previous'] < dataframe['fastd-previous']) &
|
||||||
|
(dataframe['close'] > dataframe['ema5'])
|
||||||
|
),
|
||||||
|
'sell'] = 1
|
||||||
|
return dataframe
|
156
user_data/strategies/examplefreqtrade5.py
Normal file
156
user_data/strategies/examplefreqtrade5.py
Normal file
@ -0,0 +1,156 @@
|
|||||||
|
|
||||||
|
# --- Do not remove these libs ---
|
||||||
|
from freqtrade.strategy.interface import IStrategy
|
||||||
|
from typing import Dict, List
|
||||||
|
from functools import reduce
|
||||||
|
from pandas import DataFrame
|
||||||
|
# --------------------------------
|
||||||
|
|
||||||
|
import talib.abstract as ta
|
||||||
|
import freqtrade.vendor.qtpylib.indicators as qtpylib
|
||||||
|
import numpy # noqa
|
||||||
|
|
||||||
|
|
||||||
|
class Examplestrategy5(IStrategy):
|
||||||
|
"""
|
||||||
|
Strategy 005
|
||||||
|
author@: Gerald Lonlas
|
||||||
|
github@: https://github.com/freqtrade/freqtrade-strategies
|
||||||
|
How to use it?
|
||||||
|
> python3 ./freqtrade/main.py -s Strategy005
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Minimal ROI designed for the strategy.
|
||||||
|
# This attribute will be overridden if the config file contains "minimal_roi"
|
||||||
|
minimal_roi = {
|
||||||
|
"1440": 0.01,
|
||||||
|
"80": 0.02,
|
||||||
|
"40": 0.03,
|
||||||
|
"20": 0.04,
|
||||||
|
"0": 0.05
|
||||||
|
}
|
||||||
|
|
||||||
|
# Optimal stoploss designed for the strategy
|
||||||
|
# This attribute will be overridden if the config file contains "stoploss"
|
||||||
|
stoploss = -0.10
|
||||||
|
|
||||||
|
# Optimal ticker interval for the strategy
|
||||||
|
ticker_interval = '5m'
|
||||||
|
|
||||||
|
# trailing stoploss
|
||||||
|
trailing_stop = False
|
||||||
|
trailing_stop_positive = 0.01
|
||||||
|
trailing_stop_positive_offset = 0.02
|
||||||
|
|
||||||
|
# run "populate_indicators" only for new candle
|
||||||
|
process_only_new_candles = False
|
||||||
|
|
||||||
|
# Experimental settings (configuration will overide these if set)
|
||||||
|
use_sell_signal = True
|
||||||
|
sell_profit_only = True
|
||||||
|
ignore_roi_if_buy_signal = False
|
||||||
|
|
||||||
|
# Optional order type mapping
|
||||||
|
order_types = {
|
||||||
|
'buy': 'limit',
|
||||||
|
'sell': 'limit',
|
||||||
|
'stoploss': 'market',
|
||||||
|
'stoploss_on_exchange': False
|
||||||
|
}
|
||||||
|
|
||||||
|
def informative_pairs(self):
|
||||||
|
"""
|
||||||
|
Define additional, informative pair/interval combinations to be cached from the exchange.
|
||||||
|
These pair/interval combinations are non-tradeable, unless they are part
|
||||||
|
of the whitelist as well.
|
||||||
|
For more information, please consult the documentation
|
||||||
|
:return: List of tuples in the format (pair, interval)
|
||||||
|
Sample: return [("ETH/USDT", "5m"),
|
||||||
|
("BTC/USDT", "15m"),
|
||||||
|
]
|
||||||
|
"""
|
||||||
|
return []
|
||||||
|
|
||||||
|
def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||||
|
"""
|
||||||
|
Adds several different TA indicators to the given DataFrame
|
||||||
|
Performance Note: For the best performance be frugal on the number of indicators
|
||||||
|
you are using. Let uncomment only the indicator you are using in your strategies
|
||||||
|
or your hyperopt configuration, otherwise you will waste your memory and CPU usage.
|
||||||
|
"""
|
||||||
|
|
||||||
|
# MACD
|
||||||
|
macd = ta.MACD(dataframe)
|
||||||
|
dataframe['macd'] = macd['macd']
|
||||||
|
dataframe['macdsignal'] = macd['macdsignal']
|
||||||
|
|
||||||
|
# Minus Directional Indicator / Movement
|
||||||
|
dataframe['minus_di'] = ta.MINUS_DI(dataframe)
|
||||||
|
|
||||||
|
# RSI
|
||||||
|
dataframe['rsi'] = ta.RSI(dataframe)
|
||||||
|
|
||||||
|
# Inverse Fisher transform on RSI, values [-1.0, 1.0] (https://goo.gl/2JGGoy)
|
||||||
|
rsi = 0.1 * (dataframe['rsi'] - 50)
|
||||||
|
dataframe['fisher_rsi'] = (numpy.exp(2 * rsi) - 1) / (numpy.exp(2 * rsi) + 1)
|
||||||
|
# Inverse Fisher transform on RSI normalized, value [0.0, 100.0] (https://goo.gl/2JGGoy)
|
||||||
|
dataframe['fisher_rsi_norma'] = 50 * (dataframe['fisher_rsi'] + 1)
|
||||||
|
|
||||||
|
# Stoch fast
|
||||||
|
stoch_fast = ta.STOCHF(dataframe)
|
||||||
|
dataframe['fastd'] = stoch_fast['fastd']
|
||||||
|
dataframe['fastk'] = stoch_fast['fastk']
|
||||||
|
|
||||||
|
# Overlap Studies
|
||||||
|
# ------------------------------------
|
||||||
|
|
||||||
|
# SAR Parabol
|
||||||
|
dataframe['sar'] = ta.SAR(dataframe)
|
||||||
|
|
||||||
|
# SMA - Simple Moving Average
|
||||||
|
dataframe['sma'] = ta.SMA(dataframe, timeperiod=40)
|
||||||
|
|
||||||
|
return dataframe
|
||||||
|
|
||||||
|
def populate_buy_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||||
|
"""
|
||||||
|
Based on TA indicators, populates the buy signal for the given dataframe
|
||||||
|
:param dataframe: DataFrame
|
||||||
|
:return: DataFrame with buy column
|
||||||
|
"""
|
||||||
|
dataframe.loc[
|
||||||
|
# Prod
|
||||||
|
(
|
||||||
|
(dataframe['close'] > 0.00000200) &
|
||||||
|
(dataframe['volume'] > dataframe['volume'].rolling(200).mean() * 4) &
|
||||||
|
(dataframe['close'] < dataframe['sma']) &
|
||||||
|
(dataframe['fastd'] > dataframe['fastk']) &
|
||||||
|
(dataframe['rsi'] > 0) &
|
||||||
|
(dataframe['fastd'] > 0) &
|
||||||
|
# (dataframe['fisher_rsi'] < -0.94)
|
||||||
|
(dataframe['fisher_rsi_norma'] < 38.900000000000006)
|
||||||
|
),
|
||||||
|
'buy'] = 1
|
||||||
|
|
||||||
|
return dataframe
|
||||||
|
|
||||||
|
def populate_sell_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
|
||||||
|
"""
|
||||||
|
Based on TA indicators, populates the sell signal for the given dataframe
|
||||||
|
:param dataframe: DataFrame
|
||||||
|
:return: DataFrame with buy column
|
||||||
|
"""
|
||||||
|
dataframe.loc[
|
||||||
|
# Prod
|
||||||
|
(
|
||||||
|
(qtpylib.crossed_above(dataframe['rsi'], 50)) &
|
||||||
|
(dataframe['macd'] < 0) &
|
||||||
|
(dataframe['minus_di'] > 0)
|
||||||
|
) |
|
||||||
|
(
|
||||||
|
(dataframe['sar'] > dataframe['close']) &
|
||||||
|
(dataframe['fisher_rsi'] > 0.3)
|
||||||
|
),
|
||||||
|
|
||||||
|
'sell'] = 1
|
||||||
|
return dataframe
|
Loading…
Reference in New Issue
Block a user