]>
git.immae.eu Git - perso/Immae/Projets/Cryptomonnaies/Cryptoportfolio/Trader.git/blob - main.py
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 args
= ["--config", config_path
]
65 args
.append("--debug")
66 args
= parse_args(args
)
67 pg_config
= parse_config(args
)
68 market_id
, market_config
, user_id
= list(fetch_markets(pg_config
, str(user_id
)))[0]
69 return market
.Market
.from_config(market_config
, args
,
70 pg_config
=pg_config
, market_id
=market_id
,
73 def fetch_markets(pg_config
, user
):
74 connection
= psycopg2
.connect(**pg_config
)
75 cursor
= connection
.cursor()
78 cursor
.execute("SELECT id,config,user_id FROM market_configs")
80 cursor
.execute("SELECT id,config,user_id FROM market_configs WHERE user_id = %s", user
)
85 def parse_config(args
):
90 "password": args
.db_password
,
91 "database": args
.db_database
,
99 report_path
= args
.report_path
101 if report_path
is not None and not \
102 os
.path
.exists(report_path
):
103 os
.makedirs(report_path
)
107 def parse_args(argv
):
108 parser
= configargparse
.ArgumentParser(
109 description
="Run the trade bot.")
111 parser
.add_argument("-c", "--config",
112 default
="config.ini",
113 required
=False, is_config_file
=True,
114 help="Config file to load (default: config.ini)")
115 parser
.add_argument("--before",
116 default
=False, action
='store_const', const
=True,
117 help="Run the steps before the cryptoportfolio update")
118 parser
.add_argument("--after",
119 default
=False, action
='store_const', const
=True,
120 help="Run the steps after the cryptoportfolio update")
121 parser
.add_argument("--quiet",
122 default
=False, action
='store_const', const
=True,
123 help="Don't print messages")
124 parser
.add_argument("--debug",
125 default
=False, action
='store_const', const
=True,
126 help="Run in debug mode")
127 parser
.add_argument("--user",
128 default
=None, required
=False, help="Only run for that user")
129 parser
.add_argument("--action",
131 help="Do a different action than trading (add several times to chain)")
132 parser
.add_argument("--parallel", action
='store_true', default
=True, dest
="parallel")
133 parser
.add_argument("--no-parallel", action
='store_false', dest
="parallel")
134 parser
.add_argument("--report-db", action
='store_true', default
=True, dest
="report_db",
135 help="Store report to database (default)")
136 parser
.add_argument("--no-report-db", action
='store_false', dest
="report_db",
137 help="Don't store report to database")
138 parser
.add_argument("--report-path", required
=False,
139 help="Where to store the reports (default: absent, don't store)")
140 parser
.add_argument("--no-report-path", action
='store_const', dest
='report_path', const
=None,
141 help="Don't store the report to file (default)")
142 parser
.add_argument("--db-host", default
="localhost",
143 help="Host access to database (default: localhost)")
144 parser
.add_argument("--db-port", default
=5432,
145 help="Port access to database (default: 5432)")
146 parser
.add_argument("--db-user", default
="cryptoportfolio",
147 help="User access to database (default: cryptoportfolio)")
148 parser
.add_argument("--db-password", default
="cryptoportfolio",
149 help="Password access to database (default: cryptoportfolio)")
150 parser
.add_argument("--db-database", default
="cryptoportfolio",
151 help="Database access to database (default: cryptoportfolio)")
153 return parser
.parse_args(argv
)
155 def process(market_config
, market_id
, user_id
, args
, pg_config
):
158 .from_config(market_config
, args
, market_id
=market_id
,
159 pg_config
=pg_config
, user_id
=user_id
)\
160 .process(args
.action
, before
=args
.before
, after
=args
.after
)
161 except Exception as e
:
162 print("{}: {}".format(e
.__class
__.__name
__, e
))
165 args
= parse_args(argv
)
167 pg_config
= parse_config(args
)
171 market
.Portfolio
.start_worker()
174 threading
.Thread(target
=process
, args
=args
).start()
178 for market_id
, market_config
, user_id
in fetch_markets(pg_config
, args
.user
):
179 process_(market_config
, market_id
, user_id
, args
, pg_config
)
181 if __name__
== '__main__': # pragma: no cover