profit modifier (boost)

This commit is contained in:
Nicolás Sánchez 2024-11-08 15:06:38 -03:00
parent e421e9bbde
commit 0d191edb9e
7 changed files with 79 additions and 17 deletions

View File

@ -1,3 +1,7 @@
2024.11.08:
. Added boosted take profit level: If the trader is actively closing deals, the expected profit level is raised by x%.
Defaults are: Four deals in one hour, 1% raise.
2024.11.06b:
. Added /switch_to_long_price endpoint: It displays the price at which the automatic switch_to_long routine is triggered.

View File

@ -18,5 +18,8 @@
"check_old_long_price": true, #Compares the current price with the old_long price. (check strategy documentation for more details)
"dynamic_so_deviance": true, #Uses a non-linear safety order deviance algorithm. (check strategy documentation for more details)
"dsd_range": 1, #Range of the dynamic deviance algorithm. (check strategy documentation for more details)
"bias": -0.5 #Bias of the dynamic deviance algorithm. (check strategy documentation for more details)
"bias": -0.5, #Bias of the dynamic deviance algorithm. (check strategy documentation for more details)
"boosted_deals_range": 4, #Amount of deals within a timespan to trigger the boost algorithm.
"boosted_time_range": 3600, #Timespan in seconds to count closed trades.
"boosted_amount": .1 #Amount of percentage to add to the profit target if boosted.
}

View File

@ -87,11 +87,35 @@ class broker:
return 1
def return_last_n_deals_timestamps(self, pair, amount, no_retries=False):
'''
Returns a list containing the last n deals timestamps.
'''
retries = self.retries
while retries>0:
try:
database_connection = sqlite3.connect("profits/profits_database.db")
database_cursor = database_connection.cursor()
database_cursor.execute(f"SELECT * FROM profits_table WHERE pair = '{pair}' ORDER BY timestamp DESC LIMIT {amount};")
rows = database_cursor.fetchall()
database_connection.close()
return [item[0] for item in rows]
except Exception as e:
self.logger.log_this(f"Exception in return_last_n_deals_timestamps: {e}",1)
if no_retries:
break
retries-=1
time.sleep(self.wait_time)
return []
def check_for_duplicate_profit_in_db(self,order,no_retries=False):
'''
SQLite implementation of check_for_duplicate_profit():
Compares the id of the last profit order with the one in the database.
'''
retries = self.retries
while retries>0:
try:

View File

@ -22,7 +22,7 @@ In case the permissions of the certificate changes, reset them this way:
# ll /etc/letsencrypt/
'''
version = "2024.11.06b"
version = "2024.11.08"
'''
Color definitions. If you want to change them, check the reference at https://en.wikipedia.org/wiki/ANSI_escape_code#Colors

View File

@ -3,7 +3,7 @@ import time
import json
# Connect to the SQLite database
conn = sqlite3.connect('profits/profits_database.db')
conn = sqlite3.connect('profits_database.db')
cursor = conn.cursor()
# Execute a SELECT query to retrieve data from the database
@ -17,9 +17,9 @@ rows = cursor.fetchall()
#human_time = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(int(row[0])))
#print(human_time,row[1],round(row[2],2),row[3]) # Or do whatever processing you need
data = json.loads(rows[-3][-1])
print(data[-1])
#data = json.loads(rows[-3][-1])
print([item[0] for item in rows[-4:]])
print(f"Number of entries: {len(rows)}")
# Close the connection
conn.close()
conn.close()

View File

@ -5,13 +5,8 @@ Mandatory:
2. Instead of giving a list of order_ids to each trader, give a list of the open orders and that's it (for easier future development, partial order fills for example)
3. Maintain local orderbooks for each trading pair, which enables:
3a. Smart order pricing: Prioritization of fill speed over instant profit or vice versa
4. Round-robin trading pairs: Instead of a fixed list of trading pairs, after n closed deals the trader is terminated and a new one spawns, picking the trading pair
from a pre-populated list (the trading pairs can be selected by using Yang-Zhang, Parkinson or another volatility indicator)
This could be very benefitial, since it limits the long time commitment to a small list of trading pairs, enabling the instance to react to market trends very
rapidly.
5. Consolidate vocabulary (trader, pair and bot; instance & trader)
6. Base add for short traders.
7. Dynamic take_profit level: If a trading pair is closing deals frequently, raise the take profit level to take advantage of the volatility.
4. Consolidate vocabulary (trader, pair and bot; instance & trader)
5. Base add for short traders.
Would be nice to have:
@ -19,6 +14,10 @@ Would be nice to have:
0. Trader order: alphabetical; by uptime; by safety orders, by percentage_to_completion. (Although this may be more suitable for the web and mobile apps)
1. Local implementation of amount_to_precision, cost_to_precision and price_to_precision. (Unless the plan is to continue to use CCXT forever)
2. Instead of cancelling and resending the take profit order, you could just edit it (Kucoin only supports editing on high frequency orders)
3. Round-robin trading pairs: Instead of a fixed list of trading pairs, after n closed deals the trader is terminated and a new one spawns, picking the trading pair
from a pre-populated list (the trading pairs can be selected by using Yang-Zhang, Parkinson or another volatility indicator)
This could be very benefitial, since it limits the long time commitment to a small list of trading pairs, enabling the instance to react to market trends very
rapidly.
Maybe it's a good idea?:

View File

@ -27,6 +27,7 @@ class trader:
self.check_slippage = True
if "check_slippage" in self.config_dict:
self.check_slippage = self.config_dict["check_slippage"]
self.is_boosted = False
self.start_time = int(time.time())
self.total_amount_of_quote=0
self.total_amount_of_base=1
@ -344,6 +345,7 @@ class trader:
if self.so is not None and self.so["price"] is not None and self.so!=self.broker.get_empty_order():
self.status_dict["next_so_price"]=self.so["price"]
self.status_dict["is_boosted"]=self.is_boosted
self.status_dict["is_short"]=self.is_short
self.status_dict["quote_spent"]=self.total_amount_of_quote
self.status_dict["base_bought"]=self.total_amount_of_base
@ -1276,10 +1278,35 @@ class trader:
2. Custom percentage table
3. Linear percentage table
'''
tp_level = 1
if self.is_short or self.config_dict["tp_mode"]==0: #Fixed take profit percentage
boost = 0
#BOOST ROUTINE: If the trader closed certain amount of deals within the last t timespan, raise the take profit level by x%
#Default values
boosted_deals_range = 4
boosted_time_range = 3600
boosted_amount = .01
#Load config values (if present)
if "boosted_deals_range" in self.config_dict:
boosted_deals_range = self.config_dict["boosted_deals_range"]
if "boosted_time_range" in self.config_dict:
boosted_time_range = self.config_dict["boosted_time_range"]
if "boosted_amount" in self.config_dict:
boosted_amount = self.config_dict["boosted_amount"]
self.is_boosted = False
if not self.is_short:
last_deals_timestamps = self.broker.return_last_n_deals_timestamps(self.pair,boosted_deals_range)
if len(last_deals_timestamps)==boosted_deals_range and all(item >= time.time()-boosted_time_range for item in last_deals_timestamps):
self.is_boosted = True
boost+=boosted_amount
if self.is_short or self.config_dict["tp_mode"]==0: #Fixed take profit percentage
tp_level = self.config_dict["tp_level"]
elif self.config_dict["tp_mode"]==1: #Variable percentage
elif self.config_dict["tp_mode"]==1: #Variable percentage
limit = self.config_dict["no_of_safety_orders"]/3
if order_index<=1:
tp_level = self.config_dict["tp_level"]+0.005
@ -1295,12 +1322,12 @@ class trader:
tp_level = self.config_dict["tp_table"][order_index] #Custom percentage table
tp_level = self.config_dict["tp_table"][-1]
tp_level = self.config_dict["tp_level"]
elif self.config_dict["tp_mode"]==3: #Linear percentage table
elif self.config_dict["tp_mode"]==3: #Linear percentage table
profit_table = self.linear_space(self.config_dict["tp_level"]+0.005,self.config_dict["tp_level"]-0.005,self.config_dict["no_of_safety_orders"])
tp_level = profit_table[-1]
if order_index<len(profit_table): #If more safety orders were added, instead of recalculating the whole table
tp_level = profit_table[order_index] #it just returns the last value. Otherwise, the percentage gets very small.
return 1+((tp_level-1)*multiplier)
return 1+((tp_level+boost-1)*multiplier)
def seconds_to_time(self, total_seconds: float) -> str:
@ -1701,10 +1728,13 @@ class trader:
prices = f"{red}{low_boundary}{white}|{price_color}{mid_boundary}{white}|{target_price_color}{high_boundary}{white}|{pct_color}{pct_to_profit_str}%{white}"
line1 = f"{p}{pair_color}{self.pair.center(13)}{white}| {safety_order_string} |{prices}| Uptime: {self.seconds_to_time(self.status_dict['deal_uptime'])}"
if self.is_boosted:
line1 = f"{line1} | BOOSTED"
if self.config_dict["autoswitch"]:
line1 = f"{line1} | AUTO"
if self.is_short and "old_long" in self.status_dict:
try:
#When adding a trader, this line always throws an exception since status_dict["price"] is not yet populated
percentage_to_switch = (self.status_dict["old_long"]["tp_price"]-self.status_dict["price"])*100/self.status_dict["price"]
#line1 = f"{line1} {round(percentage_to_switch,2)}%"
multiplier = int(percentage_to_switch/100)+1
@ -1748,6 +1778,8 @@ class trader:
self.start_time = self.status_dict["start_time"]
self.deal_start_time = self.status_dict["deal_start_time"]
self.stop_when_profit = self.status_dict["stop_when_profit"]
if "is_boosted" in self.status_dict:
self.is_boosted = self.status_dict["is_boosted"]
if "deal_order_history" not in self.status_dict: #No longer needed?
self.status_dict["deal_order_history"] = []