1 from datetime
import datetime
11 __all__
= ["make_order", "get_user_market"]
13 def make_order(market
, value
, currency
, action
="acquire",
14 close_if_possible
=False, base_currency
="BTC", follow
=True,
15 compute_value
="average"):
17 Make an order on market
18 "market": The market on which to place the order
19 "value": The value in *base_currency* to acquire,
20 or in *currency* to dispose.
21 use negative for margin trade.
22 "action": "acquire" or "dispose".
23 "acquire" will buy long or sell short,
24 "dispose" will sell long or buy short.
25 "currency": The currency to acquire or dispose
26 "base_currency": The base currency. The value is expressed in that
27 currency (default: BTC)
28 "follow": Whether to follow the order once run (default: True)
29 "close_if_possible": Whether to try to close the position at the end
30 of the trade, i.e. reach exactly 0 at the end
31 (only meaningful in "dispose"). May have
32 unwanted effects if the end value of the
34 "compute_value": Compute value to place the order
36 market
.report
.log_stage("make_order_begin")
37 market
.balances
.fetch_balances(tag
="make_order_begin")
38 if action
== "acquire":
39 trade
= portfolio
.Trade(
40 portfolio
.Amount(base_currency
, 0),
41 portfolio
.Amount(base_currency
, value
),
44 amount
= portfolio
.Amount(currency
, value
)
45 trade
= portfolio
.Trade(
46 amount
.in_currency(base_currency
, market
, compute_value
=compute_value
),
47 portfolio
.Amount(base_currency
, 0),
49 market
.trades
.all
.append(trade
)
50 order
= trade
.prepare_order(
51 close_if_possible
=close_if_possible
,
52 compute_value
=compute_value
)
53 market
.report
.log_orders([order
], None, compute_value
)
54 market
.trades
.run_orders()
56 market
.follow_orders()
57 market
.balances
.fetch_balances(tag
="make_order_end")
59 market
.report
.log_stage("make_order_end_not_followed")
61 market
.report
.log_stage("make_order_end")
63 def get_user_market(config_path
, user_id
, debug
=False):
64 pg_config
, report_path
= parse_config(config_path
)
65 market_id
, market_config
, user_id
= list(fetch_markets(pg_config
, str(user_id
)))[0]
66 args
= type('Args', (object,), { "debug": debug, "quiet": False }
)()
67 return market
.Market
.from_config(market_config
, args
,
68 pg_config
=pg_config
, market_id
=market_id
,
69 user_id
=user_id
, report_path
=report_path
)
71 def fetch_markets(pg_config
, user
):
72 connection
= psycopg2
.connect(**pg_config
)
73 cursor
= connection
.cursor()
76 cursor
.execute("SELECT id,config,user_id FROM market_configs")
78 cursor
.execute("SELECT id,config,user_id FROM market_configs WHERE user_id = %s", user
)
83 def parse_config(config_file
):
84 config
= configparser
.ConfigParser()
85 config
.read(config_file
)
87 if "postgresql" not in config
:
88 print("no configuration for postgresql in config file")
91 if "app" in config
and "report_path" in config
["app"]:
92 report_path
= config
["app"]["report_path"]
94 if not os
.path
.exists(report_path
):
95 os
.makedirs(report_path
)
99 return [config
["postgresql"], report_path
]
101 def parse_args(argv
):
102 parser
= argparse
.ArgumentParser(
103 description
="Run the trade bot")
105 parser
.add_argument("-c", "--config",
106 default
="config.ini",
108 help="Config file to load (default: config.ini)")
109 parser
.add_argument("--before",
110 default
=False, action
='store_const', const
=True,
111 help="Run the steps before the cryptoportfolio update")
112 parser
.add_argument("--after",
113 default
=False, action
='store_const', const
=True,
114 help="Run the steps after the cryptoportfolio update")
115 parser
.add_argument("--quiet",
116 default
=False, action
='store_const', const
=True,
117 help="Don't print messages")
118 parser
.add_argument("--debug",
119 default
=False, action
='store_const', const
=True,
120 help="Run in debug mode")
121 parser
.add_argument("--user",
122 default
=None, required
=False, help="Only run for that user")
123 parser
.add_argument("--action",
125 help="Do a different action than trading (add several times to chain)")
126 parser
.add_argument("--parallel", action
='store_true', default
=True, dest
="parallel")
127 parser
.add_argument("--no-parallel", action
='store_false', dest
="parallel")
129 args
= parser
.parse_args(argv
)
131 if not os
.path
.exists(args
.config
):
132 print("no config file found, exiting")
137 def process(market_config
, market_id
, user_id
, args
, report_path
, pg_config
):
140 .from_config(market_config
, args
,
141 pg_config
=pg_config
, market_id
=market_id
,
142 user_id
=user_id
, report_path
=report_path
)\
143 .process(args
.action
, before
=args
.before
, after
=args
.after
)
144 except Exception as e
:
145 print("{}: {}".format(e
.__class
__.__name
__, e
))
148 args
= parse_args(argv
)
150 pg_config
, report_path
= parse_config(args
.config
)
154 market
.Portfolio
.start_worker()
157 threading
.Thread(target
=process
, args
=args
).start()
161 for market_id
, market_config
, user_id
in fetch_markets(pg_config
, args
.user
):
162 process_(market_config
, market_id
, user_id
, args
, report_path
, pg_config
)
164 if __name__
== '__main__': # pragma: no cover