1 from datetime
import datetime
10 __all__
= ["make_order", "get_user_market"]
12 def make_order(market
, value
, currency
, action
="acquire",
13 close_if_possible
=False, base_currency
="BTC", follow
=True,
14 compute_value
="average"):
16 Make an order on market
17 "market": The market on which to place the order
18 "value": The value in *base_currency* to acquire,
19 or in *currency* to dispose.
20 use negative for margin trade.
21 "action": "acquire" or "dispose".
22 "acquire" will buy long or sell short,
23 "dispose" will sell long or buy short.
24 "currency": The currency to acquire or dispose
25 "base_currency": The base currency. The value is expressed in that
26 currency (default: BTC)
27 "follow": Whether to follow the order once run (default: True)
28 "close_if_possible": Whether to try to close the position at the end
29 of the trade, i.e. reach exactly 0 at the end
30 (only meaningful in "dispose"). May have
31 unwanted effects if the end value of the
33 "compute_value": Compute value to place the order
35 market
.report
.log_stage("make_order_begin")
36 market
.balances
.fetch_balances(tag
="make_order_begin")
37 if action
== "acquire":
38 trade
= portfolio
.Trade(
39 portfolio
.Amount(base_currency
, 0),
40 portfolio
.Amount(base_currency
, value
),
43 amount
= portfolio
.Amount(currency
, value
)
44 trade
= portfolio
.Trade(
45 amount
.in_currency(base_currency
, market
, compute_value
=compute_value
),
46 portfolio
.Amount(base_currency
, 0),
48 market
.trades
.all
.append(trade
)
49 order
= trade
.prepare_order(
50 close_if_possible
=close_if_possible
,
51 compute_value
=compute_value
)
52 market
.report
.log_orders([order
], None, compute_value
)
53 market
.trades
.run_orders()
55 market
.follow_orders()
56 market
.balances
.fetch_balances(tag
="make_order_end")
58 market
.report
.log_stage("make_order_end_not_followed")
60 market
.report
.log_stage("make_order_end")
62 def get_user_market(config_path
, user_id
, debug
=False):
63 pg_config
, report_path
= parse_config(config_path
)
64 market_id
, market_config
, user_id
= list(fetch_markets(pg_config
, str(user_id
)))[0]
65 args
= type('Args', (object,), { "debug": debug, "quiet": False }
)()
66 return market
.Market
.from_config(market_config
, args
,
67 pg_config
=pg_config
, market_id
=market_id
,
68 user_id
=user_id
, report_path
=report_path
)
70 def fetch_markets(pg_config
, user
):
71 connection
= psycopg2
.connect(**pg_config
)
72 cursor
= connection
.cursor()
75 cursor
.execute("SELECT id,config,user_id FROM market_configs")
77 cursor
.execute("SELECT id,config,user_id FROM market_configs WHERE user_id = %s", user
)
82 def parse_config(args
):
87 "password": args
.db_password
,
88 "database": args
.db_database
,
96 report_path
= args
.report_path
98 if report_path
is not None and not \
99 os
.path
.exists(report_path
):
100 os
.makedirs(report_path
)
104 def parse_args(argv
):
105 parser
= configargparse
.ArgumentParser(
106 description
="Run the trade bot.")
108 parser
.add_argument("-c", "--config",
109 default
="config.ini",
110 required
=False, is_config_file
=True,
111 help="Config file to load (default: config.ini)")
112 parser
.add_argument("--before",
113 default
=False, action
='store_const', const
=True,
114 help="Run the steps before the cryptoportfolio update")
115 parser
.add_argument("--after",
116 default
=False, action
='store_const', const
=True,
117 help="Run the steps after the cryptoportfolio update")
118 parser
.add_argument("--quiet",
119 default
=False, action
='store_const', const
=True,
120 help="Don't print messages")
121 parser
.add_argument("--debug",
122 default
=False, action
='store_const', const
=True,
123 help="Run in debug mode")
124 parser
.add_argument("--user",
125 default
=None, required
=False, help="Only run for that user")
126 parser
.add_argument("--action",
128 help="Do a different action than trading (add several times to chain)")
129 parser
.add_argument("--parallel", action
='store_true', default
=True, dest
="parallel")
130 parser
.add_argument("--no-parallel", action
='store_false', dest
="parallel")
131 parser
.add_argument("--report-db", action
='store_true', default
=True, dest
="report_db",
132 help="Store report to database (default)")
133 parser
.add_argument("--no-report-db", action
='store_false', dest
="report_db",
134 help="Don't store report to database")
135 parser
.add_argument("--report-path", required
=False,
136 help="Where to store the reports (default: absent, don't store)")
137 parser
.add_argument("--no-report-path", action
='store_const', dest
='report_path', const
=None,
138 help="Don't store the report to file (default)")
139 parser
.add_argument("--db-host", default
="localhost",
140 help="Host access to database (default: localhost)")
141 parser
.add_argument("--db-port", default
=5432,
142 help="Port access to database (default: 5432)")
143 parser
.add_argument("--db-user", default
="cryptoportfolio",
144 help="User access to database (default: cryptoportfolio)")
145 parser
.add_argument("--db-password", default
="cryptoportfolio",
146 help="Password access to database (default: cryptoportfolio)")
147 parser
.add_argument("--db-database", default
="cryptoportfolio",
148 help="Database access to database (default: cryptoportfolio)")
150 return parser
.parse_args(argv
)
152 def process(market_config
, market_id
, user_id
, args
, pg_config
):
155 .from_config(market_config
, args
, market_id
=market_id
,
156 pg_config
=pg_config
, user_id
=user_id
)\
157 .process(args
.action
, before
=args
.before
, after
=args
.after
)
158 except Exception as e
:
159 print("{}: {}".format(e
.__class
__.__name
__, e
))
162 args
= parse_args(argv
)
164 pg_config
= parse_config(args
)
168 market
.Portfolio
.start_worker()
171 threading
.Thread(target
=process
, args
=args
).start()
175 for market_id
, market_config
, user_id
in fetch_markets(pg_config
, args
.user
):
176 process_(market_config
, market_id
, user_id
, args
, pg_config
)
178 if __name__
== '__main__': # pragma: no cover