Early demonstration of Strategy controlling Order Type on the Exchange, Stop / Stop_limit / Market / limit etc The stake The price to submit Demo allows multiple orders to be placed, so ladding buys down to a fib Or buying and setting stop-loss Or Take profit in stages etc. Included a strategy demo with stubs for limit, market, take_profit and stop_limit orders Obviously very early code. Submitted as buys, stops etc are working / showing in GDAX. and we have hte order IDs to update trade table.
297 lines
11 KiB
Python
297 lines
11 KiB
Python
# --- Do not remove these libs ---
|
|
from freqtrade.strategy.interface import IStrategy
|
|
from pandas import DataFrame
|
|
import talib.abstract as ta
|
|
|
|
from datetime import datetime
|
|
import time
|
|
import timeit
|
|
|
|
|
|
# --------------------------------
|
|
class customorders(IStrategy):
|
|
"""
|
|
author@: Creslin
|
|
|
|
"""
|
|
minimal_roi = {
|
|
"0": 0.20
|
|
}
|
|
# Optimal stoploss designed for the strategy
|
|
stoploss = -0.01
|
|
|
|
# Optimal ticker interval for the strategy
|
|
ticker_interval = '5m'
|
|
|
|
def get_ticker_indicator(self):
|
|
return int(self.ticker_interval[:-1])
|
|
|
|
def populate_indicators(self, dataframe: DataFrame) -> DataFrame:
|
|
#
|
|
|
|
# dataframe['rsi'] = ta.RSI(dataframe, timeperiod=7)
|
|
time.sleep(1)
|
|
|
|
return dataframe
|
|
|
|
# # # If using Berlins expose pairs to strategy
|
|
# def advise_indicators(self, dataframe: DataFrame, pair: str) -> DataFrame:
|
|
#
|
|
# # RSI
|
|
# dataframe['rsi'] = ta.RSI(dataframe, timeperiod=7)
|
|
#
|
|
# return dataframe
|
|
|
|
#####
|
|
# EXAMPLE Strat - buys every even minute sells every odd
|
|
####
|
|
def populate_buy_trend(self, dataframe: DataFrame) -> DataFrame:
|
|
if int(datetime.now().strftime('%M')) % 2 == 0: #buy = 1 every even minute
|
|
print('----------------we are in strategy', datetime.now().time())
|
|
b: float = 9999999.99
|
|
print( "buy = 1")
|
|
else:
|
|
b = 0.00000001
|
|
dataframe.loc[
|
|
(
|
|
# L-RSI When below 0.01 / vfi -26
|
|
#(dataframe['lrsi'] < 0.5) &
|
|
#(dataframe['vfi'] < -4)
|
|
(dataframe['close'] < b )
|
|
),
|
|
'buy'] = 1
|
|
return dataframe
|
|
|
|
#####
|
|
# EXAMPLE Strat - buys every even minute sells every odd
|
|
####
|
|
def populate_sell_trend(self, dataframe: DataFrame) -> DataFrame:
|
|
if int(datetime.now().strftime('%M'))% 2 != 0: ## sell = 1 every ODD minute
|
|
print('----------------we are in strategy', datetime.now().time())
|
|
s: float = 9999999.99
|
|
print("sell = 1")
|
|
else:
|
|
s = 0.00000001
|
|
dataframe.loc[
|
|
(
|
|
# vfi 0.99
|
|
#(dataframe['vfi'] > 0.41)
|
|
(dataframe['close'] < s )
|
|
),
|
|
'sell'] = 1
|
|
return dataframe
|
|
|
|
def stop_stops_plugin(self, dataframe: DataFrame, pair: str) -> DataFrame:
|
|
"""
|
|
stop_stops_pligin. To stop a buy where X trades from Y have stopped out.
|
|
i.e to remove a pair from being bought that is on a losing streak.
|
|
|
|
Only processed if buy=1
|
|
"""
|
|
"""
|
|
Called before a trade executes if exists,
|
|
:param dataframe:
|
|
:param pair:
|
|
:return:
|
|
"""
|
|
|
|
from freqtrade.persistence import Trade
|
|
import pandas as pd
|
|
df = dataframe
|
|
|
|
# Only check buys, else return DF untouched
|
|
|
|
if df.iloc[-1]['buy'] == 1:
|
|
|
|
print("STOP_STOPS STOP_STOPS STOP_STOPS STOP_STOP STOP_STOPS STOP_STOP STOP_STOPS")
|
|
|
|
from pandas import set_option
|
|
set_option('display.max_rows', 2000)
|
|
set_option('display.max_columns', 8)
|
|
|
|
def closed_pair_trades(pair):
|
|
"""
|
|
To return list of closed trades for a pair
|
|
enriched with open/closd dates, profit, and stake
|
|
|
|
:param pair:
|
|
:return: df_c pair open, close, profit, stake
|
|
"""
|
|
pair = pair
|
|
df_c = pd.DataFrame(columns=['pair', 'profit', 'open_date', 'close_date', 'stake'])
|
|
|
|
pair_trades = Trade.query.filter(Trade.pair.is_(pair)).all()
|
|
for pair_trade in pair_trades:
|
|
if pair_trade.is_open == False:
|
|
# print("closed trade for", pair, "closed with ", pair_trade.close_profit )
|
|
|
|
p = pair
|
|
pcp = pair_trade.close_profit
|
|
od = pair_trade.open_date
|
|
cd = pair_trade.close_date
|
|
sa = pair_trade.stake_amount
|
|
|
|
df_c = df_c.append([{'pair':p, 'profit':pcp, 'open_date':od,
|
|
'close_date':cd, 'stake':sa}], ignore_index=True)
|
|
return df_c
|
|
|
|
def has_past_perf(df_c, lost_the_last=1, out_of=1):
|
|
"""
|
|
Return if pair lost_the_last X trades out_of Y trades
|
|
:param df_c: dataframe of closed trades for the pair
|
|
:param lost_the_last: number of bad trades to look for
|
|
:param out_of: within the last number over trades closed
|
|
:return: bool
|
|
"""
|
|
lost_the_last =lost_the_last
|
|
out_of = out_of
|
|
df_c = df_c
|
|
|
|
df_c_tail = df_c.tail(out_of)
|
|
lost_from_last_count = df_c_tail[df_c_tail['profit'] < 0].shapec
|
|
if lost_from_last_count[0] >= lost_the_last:
|
|
return True
|
|
else:
|
|
return False
|
|
|
|
# load this pairs closed trades into a df
|
|
# df_c = closed_pair_trades(pair=pair)
|
|
# print("df_c", df_c)
|
|
|
|
# Get bool if on pairs past profitable trades count, cancel the buy if limit hit
|
|
# past_perf = has_past_perf(df_c, lost_the_last=9, out_of=10)
|
|
# if past_perf:
|
|
# #set buy to 0
|
|
# print("STOP STOP SETTING BUY TO ZERO ")
|
|
# df.loc['buy'] = 0
|
|
|
|
dataframe = df
|
|
return dataframe
|
|
|
|
#def money_mgt_plugin(self, dataframe: DataFrame, pair: str) -> DataFrame:
|
|
def money_mgt_plugin(self, dataframe: DataFrame, pair: str) -> DataFrame:
|
|
"""
|
|
pre_trade_mgt.
|
|
To allow money mamagement and or other checks to be put against dataframe
|
|
with buy or sell set to "1"
|
|
|
|
Returns a list of custom order trades.
|
|
Each custom order to include, above the needed fields for exchange
|
|
|
|
dict['order_type'] = 'a_open_limit'
|
|
|
|
order_types are later ordered and executed in alphabetical order.
|
|
order to enter market are executed before stops and take profits are played in.
|
|
Supported types are:
|
|
- a_open_limit # enter market with limit order
|
|
- a_open_market # enter market with market order
|
|
- b_stop_limit # set a stop_limit order
|
|
- b_stop_market # set a stop_market order
|
|
- c_take_limit # set a take profit limit order
|
|
- c_take_market # set a take profit market order
|
|
|
|
Multipe orders can be processed but an asset may only have the sum of its open value
|
|
in either stop or take profit orders.
|
|
|
|
i.e we can open a $500 for 500 tokens position and have any combination of
|
|
stop or take profit orders at any prices that COMBINED do not break 500 tokens.
|
|
|
|
"one" common scenario may be an 'a_open_limit' or 'a_open_market' order
|
|
and 'b_stop_limit' or 'b_stop_market' order to protect capital.
|
|
|
|
"""
|
|
print("MONEY_MGT MONEY_MGT MONEY_MGT MONEY_MGT MONEY_MGT MONEY_MGT MONEY_MGT MONEY_MGT MONEY_MGT")
|
|
df = dataframe
|
|
|
|
# If buy = 1 and Exchange is GDAX
|
|
if df.iloc[-1]['buy'] == 1:
|
|
exchange = self.config['exchange']['name']
|
|
|
|
# GDAX Stop-Limit Order
|
|
if exchange == "gdax":
|
|
|
|
custom_orders = []
|
|
limit = {}
|
|
take_profit = {}
|
|
|
|
# Take profit Market example "b_take_market"
|
|
# open market order example "a_open_market"
|
|
|
|
# Open limit order example
|
|
amount = 0.5
|
|
limit_price = df.iloc[-1]['close'] * 1.05 # pay 5% for testing order are made
|
|
|
|
limit = {}
|
|
limit["order_type"] = "a_open_limit"
|
|
limit["symbol"] = pair
|
|
limit["type"] = "limit"
|
|
limit["side"] = "buy"
|
|
limit["amount"] = amount
|
|
limit["price"] = limit_price
|
|
params: dict = {}
|
|
limit["params"] = params
|
|
|
|
custom_orders.append(limit)
|
|
|
|
# Market Example
|
|
market_amount = 1
|
|
|
|
market = {}
|
|
market_price = 1.05 # pay 5% for testing order are made
|
|
market["order_type"] = "a_open_market"
|
|
market["symbol"] = pair
|
|
market["type"] = "market"
|
|
market["side"] = "buy"
|
|
market["amount"] = market_amount
|
|
params: dict = {}
|
|
market["params"] = params
|
|
|
|
custom_orders.append(market)
|
|
|
|
# Stop Limit order
|
|
stop_limit = {}
|
|
stop_limit_amount = 0.01
|
|
stop_limit_price = df.iloc[-1]['close'] * 0.90 # take 10% hard code for testing
|
|
stop_price = df.iloc[-1]['close'] * 0.95 # trigger at 7% loss, hard code for testing
|
|
|
|
stop_limit['order_type'] = 'b_stop_limit'
|
|
stop_limit['symbol'] = pair
|
|
stop_limit['type'] = 'limit'
|
|
stop_limit['side'] = 'sell'
|
|
stop_limit['amount'] = stop_limit_amount
|
|
stop_limit['price'] = stop_limit_price
|
|
params: dict = {}
|
|
params['stop'] = 'loss'
|
|
params['stop_price'] = stop_price
|
|
stop_limit['params'] = params
|
|
|
|
custom_orders.append(stop_limit)
|
|
|
|
# Take profit Limit example
|
|
take_profit_limit_price = df.iloc[-1]['close'] * 1.2 # take_proft at 20% - for demo
|
|
take_profit_amount = 0.01
|
|
|
|
take_profit["order_type"] = "c_take_profit_limit"
|
|
take_profit["order_template"] = (pair, amount, take_profit_limit_price)
|
|
take_profit["symbol"] = pair
|
|
take_profit["type"] = "limit"
|
|
take_profit["side"] = "sell"
|
|
take_profit["amount"] = take_profit_amount
|
|
take_profit["price"] = take_profit_limit_price
|
|
take_profit_params: dict = {}
|
|
take_profit["params"] = take_profit_params
|
|
|
|
# custom_orders.append(take_profit)
|
|
|
|
#todo Add library of trade templates for binance, polo, gdax...
|
|
#todo Code to check have all the fields and sense check
|
|
|
|
# Cancel Legacy buy/sell signals if there are custom orders.
|
|
# Set buy / sell = 0 if we have custom orders
|
|
dataframe.loc['buy'] = 0
|
|
dataframe.loc['sell'] = 0
|
|
|
|
return dataframe, custom_orders
|
|
|
|
return dataframe, None
|