Skip to content

Commit

Permalink
Merge pull request #404 from enarjord/v5.9.8
Browse files Browse the repository at this point in the history
v5.9.8 forager separate long/short
  • Loading branch information
enarjord authored May 25, 2023
2 parents 80b2d63 + 28298df commit 2fdd227
Show file tree
Hide file tree
Showing 6 changed files with 146 additions and 51 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

:warning: **Use at own risk** :warning:

v5.9.7
v5.9.8


## Overview
Expand Down
2 changes: 1 addition & 1 deletion auto_profit_transfer.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ async def main():
transferred = await bot.transfer_from_derivatives_to_spot(args.quote, to_transfer)
logging.info(f"income: {profit} transferred {to_transfer} {args.quote}")
if exchange == "bybit":
if "ret_msg" not in transferred or transferred["ret_msg"] != "OK":
if "ret_msg" not in transferred or transferred["ret_msg"] not in ["OK", "success"]:
print(f"error with transfer {transferred}")
continue
logging.info(f"{transferred}")
Expand Down
28 changes: 19 additions & 9 deletions configs/forager/example_config.hjson
Original file line number Diff line number Diff line change
Expand Up @@ -27,22 +27,32 @@
// if symbol is missing from live_configs_map, default to this config
default_config_path: configs/live/clock_mode.example.json

// if true, allow only symbols present in live_configs_map
// if true, allow only symbols present in live_configs_map or live_configs_map_{long/short}
// if false, will use default_config_path when symbol is missing from live_configs_map
approved_symbols_only: false

// if symbol is present in live_configs_map_{long/short}, use that config for {long/short}
// elif symbol is present in live_configs_map, use that config for {long/short}
// else use default_config_path for {long/short}

live_configs_map: {
BTCUSDT: configs/live/clock_mode.example.json
ETHUSDT: configs/live/neat_grid_mode.example.json
DOGEUSDT: configs/live/recursive_grid_mode.example.json
}

// min markup when -gs
gs_mm: null
// markup range when -gs
gs_mr: null
// long WE_limit when -gs
gs_lw: null
// short WE_limit when -gs
gs_sw: null
// will override long configs from live_configs_map
live_configs_map_long: {
BTCUSDT: configs/live/clock_mode.example.json
XMRUSDT: configs/live/neat_grid_mode.example.json
XRPUSDT: configs/live/recursive_grid_mode.example.json
}

// will override short configs from live_configs_map
live_configs_map_short: {
BTCUSDT: configs/live/clock_mode.example.json
ETHUSDT: configs/live/neat_grid_mode.example.json
DOGEUSDT: configs/live/recursive_grid_mode.example.json
}

}
127 changes: 87 additions & 40 deletions forager.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import traceback
from procedures import load_exchange_key_secret_passphrase, utc_ms
from njit_funcs import calc_emas
from pure_funcs import determine_pos_side_ccxt


def score_func_old(ohlcv):
Expand Down Expand Up @@ -101,8 +102,14 @@ def generate_yaml(
sorted_syms = [x[1] for x in sorted_syms]
current_positions_long = sorted(set(current_positions_long + current_open_orders_long))
current_positions_short = sorted(set(current_positions_short + current_open_orders_short))
ideal_longs = sorted_syms[:n_longs]
ideal_shorts = sorted_syms[:n_shorts]
if config["approved_symbols_only"]:
approved_longs = set(config["live_configs_map_long"]) | set(config["live_configs_map"])
approved_shorts = set(config["live_configs_map_short"]) | set(config["live_configs_map"])
else:
approved_longs = set(sorted_syms)
approved_shorts = set(sorted_syms)
ideal_longs = [x for x in sorted_syms if x in approved_longs][:n_longs]
ideal_shorts = [x for x in sorted_syms if x in approved_shorts][:n_shorts]

free_slots_long = max(0, n_longs - len(current_positions_long))
active_longs = [sym for sym in ideal_longs if sym in current_positions_long]
Expand All @@ -128,42 +135,66 @@ def generate_yaml(
active_bots.append(elm)
else:
bots_on_gs.append(elm)
for z in range(0, len(active_bots), config["max_n_panes"]):
active_bots_slice = active_bots[z : z + config["max_n_panes"]]
yaml += f"- window_name: {config['user']}_normal_{z}\n layout: "
yaml += f"even-vertical\n shell_command_before:\n - cd ~/passivbot\n panes:\n"
for sym, long_enabled, short_enabled in active_bots_slice:
lm = "n" if long_enabled and lw > 0.0 else "gs"
sm = "n" if short_enabled and sw > 0.0 else "gs"
conf_path = (
config["live_configs_map"][sym] if sym in config["live_configs_map"] else config["default_config_path"]
)
pane = f" - shell_command:\n - python3 passivbot.py {user} {sym} {conf_path} "

bot_instances = []
for sym, long_enabled, short_enabled in active_bots + bots_on_gs:
lm = "n" if long_enabled and lw > 0.0 else "gs"
sm = "n" if short_enabled and sw > 0.0 else "gs"
if sym in config["live_configs_map_long"]:
conf_path_long = config["live_configs_map_long"][sym]
elif sym in config["live_configs_map"]:
conf_path_long = config["live_configs_map"][sym]
else:
conf_path_long = config["default_config_path"]

if sym not in (shorts_on_gs + active_shorts):
conf_path_short = conf_path_long
elif sym in config["live_configs_map_short"]:
conf_path_short = config["live_configs_map_short"][sym]
elif sym in config["live_configs_map"]:
conf_path_short = config["live_configs_map"][sym]
else:
conf_path_short = config["default_config_path"]

if sym not in (longs_on_gs + active_longs):
conf_path_long = conf_path_short

if conf_path_long == conf_path_short:
pane = f" - shell_command:\n - python3 passivbot.py {user} {sym} {conf_path_long} "
pane += f"-lw {lw} -sw {sw} -lm {lm} -sm {sm} -lev {config['leverage']} -cd -pt {config['price_distance_threshold']}"
yaml += pane + "\n"
if bots_on_gs:
for z in range(0, len(bots_on_gs), config["max_n_panes"]):
bots_on_gs_slice = bots_on_gs[z : z + config["max_n_panes"]]
yaml += (
f"- window_name: {config['user']}_gs_{z}\n layout: even-vertical\n shell_command_before:\n - cd ~/passivbot\n panes:"
+ "\n"
)
gs_lw = lw if config["gs_lw"] is None else config["gs_lw"]
gs_sw = lw if config["gs_sw"] is None else config["gs_sw"]
for sym, _, _ in bots_on_gs_slice:
conf_path = (
config["live_configs_map"][sym]
if sym in config["live_configs_map"]
else config["default_config_path"]
)
pane = f" - shell_command:\n - python3 passivbot.py {user} {sym} {conf_path} -lw {gs_lw} "
pane += (
f"-sw {gs_sw} -lm gs -sm gs -lev {config['leverage']} -cd -pt {config['price_distance_threshold']}"
)
for k0, k1 in [("lmm", "gs_mm"), ("lmr", "gs_mr")]:
if config[k1] is not None:
pane += f" -{k0} {config[k1]}"
yaml += pane + "\n"
bot_instances.append((sym, pane))
else:
# long and short use different configs
long_active = sym in active_longs or sym in current_positions_long
short_active = sym in active_shorts or sym in current_positions_short
if long_active and short_active:
# two separate bot instances for long & short
pane = f" - shell_command:\n - python3 passivbot.py {user} {sym} {conf_path_long} "
pane += f"-lw {lw} -sw {sw} -lm {lm} -sm m -lev {config['leverage']} -cd -pt {config['price_distance_threshold']}"
bot_instances.append((sym, pane))
pane = f" - shell_command:\n - python3 passivbot.py {user} {sym} {conf_path_short} "
pane += f"-lw {lw} -sw {sw} -lm m -sm {sm} -lev {config['leverage']} -cd -pt {config['price_distance_threshold']}"
bot_instances.append((sym, pane))
elif long_active:
pane = f" - shell_command:\n - python3 passivbot.py {user} {sym} {conf_path_long} "
pane += f"-lw {lw} -sw {sw} -lm {lm} -sm {sm} -lev {config['leverage']} -cd -pt {config['price_distance_threshold']}"
bot_instances.append((sym, pane))
elif short_active:
pane = f" - shell_command:\n - python3 passivbot.py {user} {sym} {conf_path_short} "
pane += f"-lw {lw} -sw {sw} -lm {lm} -sm {sm} -lev {config['leverage']} -cd -pt {config['price_distance_threshold']}"
bot_instances.append((sym, pane))

both_on_gs = False
z = 0
for sym, pane in bot_instances:
if not both_on_gs and sym not in active_longs and sym not in active_shorts:
z = 0
both_on_gs = True
if z % config["max_n_panes"] == 0:
yaml += f"- window_name: {config['user']}_{'gs' if both_on_gs else 'normal'}_{z}\n layout: "
yaml += f"even-vertical\n shell_command_before:\n - cd ~/passivbot\n panes:\n"
yaml += pane + "\n"
z += 1
return yaml


Expand Down Expand Up @@ -228,15 +259,21 @@ async def get_current_symbols(cc):
oos = await cc.fetch_open_orders()
current_open_orders_long, current_open_orders_short = [], []
for elm in oos:
if elm["side"] == "short":
pos_side = determine_pos_side_ccxt(elm)
if pos_side == "short":
current_open_orders_short.append(elm["symbol"])
else:
current_open_orders_long.append(elm["symbol"])
current_positions_long = sorted(set(current_positions_long))
current_positions_short = sorted(set(current_positions_short))
current_open_orders_long = sorted(set(current_open_orders_long))
current_open_orders_short = sorted(set(current_open_orders_short))
return current_positions_long, current_positions_short, current_open_orders_long, current_open_orders_short
return (
current_positions_long,
current_positions_short,
current_open_orders_long,
current_open_orders_short,
)


async def get_min_costs(cc):
Expand Down Expand Up @@ -284,7 +321,15 @@ async def dump_yaml(cc, config):
approved = sorted(set(approved) - set(config["symbols_to_ignore"]))
if config["approved_symbols_only"]:
# only use approved symbols
approved = sorted(set(approved) & set(config["live_configs_map"]))
approved = sorted(
set(approved)
& (
set(config["live_configs_map"])
| set(config["live_configs_map_long"])
| set(config["live_configs_map_short"])
)
)

print("getting current bots...")
(
current_positions_long,
Expand Down Expand Up @@ -353,6 +398,8 @@ async def main():
("ohlcv_interval", "15m"),
("leverage", 10),
("symbols_to_ignore", []),
("live_configs_map_long", {}),
("live_configs_map_short", {}),
]:
if key not in config:
config[key] = value
Expand Down
1 change: 1 addition & 0 deletions passivbot.py
Original file line number Diff line number Diff line change
Expand Up @@ -1418,6 +1418,7 @@ async def start_ohlcv_mode(self):
res = self.calc_minutes_until_next_orders()
if do_long:
line += f"entry long: {res['entry_long']:.1f}, close long: {res['close_long']:.1f}"
line += " | " if do_short else ""
if do_short:
line += f"entry short: {res['entry_short']:.1f}, close short: {res['close_short']:.1f}"
except Exception as e:
Expand Down
37 changes: 37 additions & 0 deletions pure_funcs.py
Original file line number Diff line number Diff line change
Expand Up @@ -1563,3 +1563,40 @@ def shorten_custom_id(id_: str) -> str:
]:
id0 = id0.replace(k_, r_)
return id0


def determine_pos_side_ccxt(open_order: dict) -> str:
oo = open_order["info"]
keys_map = {key.lower().replace("_", ""): key for key in oo}
for poskey in ["posside", "positionside"]:
if poskey in keys_map:
return oo[keys_map[poskey]].lower()
if oo["side"].lower() == "buy":
if "reduceonly" in keys_map:
if oo[keys_map["reduceonly"]]:
return "short"
else:
return "long"
if "closedsize" in keys_map:
if float(oo[keys_map["closedsize"]]) != 0.0:
return "short"
else:
return "long"
if oo["side"].lower() == "sell":
if "reduceonly" in keys_map:
if oo[keys_map["reduceonly"]]:
return "long"
else:
return "short"
if "closedsize" in keys_map:
if float(oo[keys_map["closedsize"]]) != 0.0:
return "long"
else:
return "short"
for key in ["order_link_id", "clOrdId", "clientOid"]:
if key in oo:
if "long" in oo[key] or "lng" in oo[key]:
return "long"
if "short" in oo[key] or "shrt" in oo[key]:
return "short"
return "both"

0 comments on commit 2fdd227

Please sign in to comment.