]>
git.immae.eu Git - perso/Immae/Projets/Cryptomonnaies/Cryptoportfolio/Trader.git/blob - main.py
9 __all__
= ["make_order", "get_user_market"]
11 def make_order(market
, value
, currency
, action
="acquire",
12 close_if_possible
=False, base_currency
="BTC", follow
=True,
13 compute_value
="average"):
15 Make an order on market
16 "market": The market on which to place the order
17 "value": The value in *base_currency* to acquire,
18 or in *currency* to dispose.
19 use negative for margin trade.
20 "action": "acquire" or "dispose".
21 "acquire" will buy long or sell short,
22 "dispose" will sell long or buy short.
23 "currency": The currency to acquire or dispose
24 "base_currency": The base currency. The value is expressed in that
25 currency (default: BTC)
26 "follow": Whether to follow the order once run (default: True)
27 "close_if_possible": Whether to try to close the position at the end
28 of the trade, i.e. reach exactly 0 at the end
29 (only meaningful in "dispose"). May have
30 unwanted effects if the end value of the
32 "compute_value": Compute value to place the order
34 market
.report
.log_stage("make_order_begin")
35 market
.balances
.fetch_balances(tag
="make_order_begin")
36 if action
== "acquire":
37 trade
= portfolio
.Trade(
38 portfolio
.Amount(base_currency
, 0),
39 portfolio
.Amount(base_currency
, value
),
42 amount
= portfolio
.Amount(currency
, value
)
43 trade
= portfolio
.Trade(
44 amount
.in_currency(base_currency
, market
, compute_value
=compute_value
),
45 portfolio
.Amount(base_currency
, 0),
47 market
.trades
.all
.append(trade
)
48 order
= trade
.prepare_order(
49 close_if_possible
=close_if_possible
,
50 compute_value
=compute_value
)
51 market
.report
.log_orders([order
], None, compute_value
)
52 market
.trades
.run_orders()
54 market
.follow_orders()
55 market
.balances
.fetch_balances(tag
="make_order_end")
57 market
.report
.log_stage("make_order_end_not_followed")
59 market
.report
.log_stage("make_order_end")
61 def get_user_market(config_path
, user_id
, debug
=False):
62 args
= ["--config", config_path
]
64 args
.append("--debug")
65 args
= parse_args(args
)
66 pg_config
= parse_config(args
)
67 market_id
, market_config
, user_id
= list(fetch_markets(pg_config
, str(user_id
)))[0]
68 return market
.Market
.from_config(market_config
, args
,
69 pg_config
=pg_config
, market_id
=market_id
,
72 def fetch_markets(pg_config
, user
):
73 connection
= psycopg2
.connect(**pg_config
)
74 cursor
= connection
.cursor()
77 cursor
.execute("SELECT id,config,user_id FROM market_configs")
79 cursor
.execute("SELECT id,config,user_id FROM market_configs WHERE user_id = %s", user
)
84 def parse_config(args
):
89 "password": args
.db_password
,
90 "database": args
.db_database
,
98 report_path
= args
.report_path
100 if report_path
is not None and not \
101 os
.path
.exists(report_path
):
102 os
.makedirs(report_path
)
106 def parse_args(argv
):
107 parser
= configargparse
.ArgumentParser(
108 description
="Run the trade bot.")
110 parser
.add_argument("-c", "--config",
111 default
="config.ini",
112 required
=False, is_config_file
=True,
113 help="Config file to load (default: config.ini)")
114 parser
.add_argument("--before",
115 default
=False, action
='store_const', const
=True,
116 help="Run the steps before the cryptoportfolio update")
117 parser
.add_argument("--after",
118 default
=False, action
='store_const', const
=True,
119 help="Run the steps after the cryptoportfolio update")
120 parser
.add_argument("--quiet",
121 default
=False, action
='store_const', const
=True,
122 help="Don't print messages")
123 parser
.add_argument("--debug",
124 default
=False, action
='store_const', const
=True,
125 help="Run in debug mode")
126 parser
.add_argument("--user",
127 default
=None, required
=False, help="Only run for that user")
128 parser
.add_argument("--action",
130 help="Do a different action than trading (add several times to chain)")
131 parser
.add_argument("--parallel", action
='store_true', default
=True, dest
="parallel")
132 parser
.add_argument("--no-parallel", action
='store_false', dest
="parallel")
133 parser
.add_argument("--report-db", action
='store_true', default
=True, dest
="report_db",
134 help="Store report to database (default)")
135 parser
.add_argument("--no-report-db", action
='store_false', dest
="report_db",
136 help="Don't store report to database")
137 parser
.add_argument("--report-path", required
=False,
138 help="Where to store the reports (default: absent, don't store)")
139 parser
.add_argument("--no-report-path", action
='store_const', dest
='report_path', const
=None,
140 help="Don't store the report to file (default)")
141 parser
.add_argument("--db-host", default
="localhost",
142 help="Host access to database (default: localhost)")
143 parser
.add_argument("--db-port", default
=5432,
144 help="Port access to database (default: 5432)")
145 parser
.add_argument("--db-user", default
="cryptoportfolio",
146 help="User access to database (default: cryptoportfolio)")
147 parser
.add_argument("--db-password", default
="cryptoportfolio",
148 help="Password access to database (default: cryptoportfolio)")
149 parser
.add_argument("--db-database", default
="cryptoportfolio",
150 help="Database access to database (default: cryptoportfolio)")
152 return parser
.parse_args(argv
)
154 def process(market_config
, market_id
, user_id
, args
, pg_config
):
157 .from_config(market_config
, args
, market_id
=market_id
,
158 pg_config
=pg_config
, user_id
=user_id
)\
159 .process(args
.action
, before
=args
.before
, after
=args
.after
)
160 except Exception as e
:
161 print("{}: {}".format(e
.__class
__.__name
__, e
))
164 args
= parse_args(argv
)
166 pg_config
= parse_config(args
)
168 market
.Portfolio
.report
.set_verbose(not args
.quiet
)
172 market
.Portfolio
.start_worker()
176 thread
= threading
.Thread(target
=process
, args
=args
)
178 threads
.append(thread
)
182 for market_id
, market_config
, user_id
in fetch_markets(pg_config
, args
.user
):
183 process_(market_config
, market_id
, user_id
, args
, pg_config
)
186 for thread
in threads
:
188 market
.Portfolio
.stop_worker()
190 if __name__
== '__main__': # pragma: no cover