def run(self): """ Threaded main function :return: None """ try: TelegramHandler.send_msg('*Status:* `trader started`') logger.info('Trader started') while not _should_stop: try: self._process() except (ConnectionError, JSONDecodeError, ValueError) as error: msg = 'Got {} during _process()'.format( error.__class__.__name__) logger.exception(msg) finally: Session.flush() time.sleep(25) except (RuntimeError, JSONDecodeError) as e: TelegramHandler.send_msg( '*Status:* Got RuntimeError: ```\n{}\n```'.format( traceback.format_exc())) logger.exception('RuntimeError. Stopping trader ...') finally: TelegramHandler.send_msg('*Status:* `Trader has stopped`')
def __init__(self, debug=False, host='0.0.0.0', port=5000): self.app = Flask(__name__, static_folder=os.path.join(os.getcwd(), ONG_FOLDER), static_url_path=os.path.join(HOST, ONG_FOLDER)) self.app_config() self.host = host self.port = port self.debug = debug self.session = Session()
def close_trade_if_fulfilled(trade: Trade) -> bool: """ Checks if the trade is closable, and if so it is being closed. :param trade: Trade :return: True if trade has been closed else False """ # If we don't have an open order and the close rate is already set, # we can close this trade. if trade.close_profit and trade.close_date and trade.close_rate and not trade.open_order_id: trade.is_open = False Session.flush() return True return False
def _performance(bot: Bot, update: Update) -> None: """ Handler for /performance. Shows a performance statistic from finished trades :param bot: telegram bot :param update: message update :return: None """ from main import get_instance if not get_instance().is_alive(): TelegramHandler.send_msg('`trader is not running`', bot=bot) return pair_rates = Session.query(Trade.pair, func.sum(Trade.close_profit).label('profit_sum')) \ .filter(Trade.is_open.is_(False)) \ .group_by(Trade.pair) \ .order_by('profit_sum DESC') \ .all() stats = '\n'.join( '{}. <code>{}\t{}%</code>'.format(i + 1, pair, round(rate, 2)) for i, (pair, rate) in enumerate(pair_rates)) message = '<b>Performance:</b>\n{}\n'.format(stats) logger.debug(message) TelegramHandler.send_msg(message, parse_mode=ParseMode.HTML)
def _process() -> None: """ Queries the persistence layer for open trades and handles them, otherwise a new trade is created. :return: None """ # Query trades from persistence layer trades = Trade.query.filter(Trade.is_open.is_(True)).all() if len(trades) < CONFIG['max_open_trades']: try: # Create entity and execute trade trade = create_trade(float(CONFIG['stake_amount']), api_wrapper.exchange) if trade: Session.add(trade) else: logging.info('Got no buy signal...') except ValueError: logger.exception('Unable to create trade') for trade in trades: # Check if there is already an open order for this trade orders = api_wrapper.get_open_orders(trade.pair) orders = [o for o in orders if o['id'] == trade.open_order_id] if orders: msg = 'There exists an open order for {}: Order(total={}, remaining={}, type={}, id={})' \ .format( trade, round(orders[0]['amount'], 8), round(orders[0]['remaining'], 8), orders[0]['type'], orders[0]['id']) logger.info(msg) continue # Update state trade.open_order_id = None # Check if this trade can be marked as closed if close_trade_if_fulfilled(trade): logger.info( 'No open orders found and trade is fulfilled. Marking %s as closed ...', trade) continue # Check if we can sell our current pair handle_trade(trade)
def main(): documents_dict = gather_all_documents() # save documents documents_mod = list(map(convert_to_document, documents_dict)) new_documents = remove_duplicates(documents_mod) session = Session() session.bulk_save_objects(new_documents) try: session.commit() except Exception as ex: session.rollback() finally: session.close() for doc in new_documents: doc.download()
def _profit(bot: Bot, update: Update) -> None: """ Handler for /profit. Returns a cumulative profit statistics. :param bot: telegram bot :param update: message update :return: None """ trades = Trade.query.order_by(Trade.id).all() profit_amounts = [] profits = [] durations = [] for trade in trades: if trade.close_date: durations.append( (trade.close_date - trade.open_date).total_seconds()) if trade.close_profit: profit = trade.close_profit else: # Get current rate current_rate = api_wrapper.get_ticker(trade.pair)['bid'] profit = 100 * ( (current_rate - trade.open_rate) / trade.open_rate) profit_amounts.append((profit / 100) * trade.btc_amount) profits.append(profit) bp_pair, bp_rate = Session.query(Trade.pair, func.sum(Trade.close_profit).label('profit_sum')) \ .filter(Trade.is_open.is_(False)) \ .group_by(Trade.pair) \ .order_by('profit_sum DESC') \ .first() markdown_msg = """ *ROI:* `{profit_btc} ({profit}%)` *Trade Count:* `{trade_count}` *First Trade opened:* `{first_trade_date}` *Latest Trade opened:* `{latest_trade_date}` *Avg. Duration:* `{avg_duration}` *Best Performing:* `{best_pair}: {best_rate}%` """.format( profit_btc=round(sum(profit_amounts), 8), profit=round(sum(profits), 2), trade_count=len(trades), first_trade_date=arrow.get(trades[0].open_date).humanize(), latest_trade_date=arrow.get(trades[-1].open_date).humanize(), avg_duration=str( timedelta(seconds=sum(durations) / float(len(durations)))).split('.')[0], best_pair=bp_pair, best_rate=round(bp_rate, 2), ) TelegramHandler.send_msg(markdown_msg, bot=bot)
def main(): log.info("------------------------------------------------------------") session = Session() (options, args) = parser.parse_args() if options.filename is not None: feeds = [options.filename] else: feeds = settings.get('main', 'feeds').split() preferred_quality = settings.get('main', 'preferred_quality') if settings.has_option('main', 'global_exclude_regex'): exclude_regex = re.compile(settings.get('main', 'global_exclude_regex')) else: exclude_regex = None for feed_url in feeds: feed = parse(feed_url) log.info("Checking %s" % feed['feed']['subtitle']) for entry in feed.entries: if (exclude_regex is not None and exclude_regex.search(entry.description.lower()) is not None): log.info("SKIP %s" % entry.description) continue data = extract_metadata(entry.description) try: data['torrent_url'] = entry.enclosures[0]['href'] except (IndexError, KeyError): log.warning("No torrent found for %(name)s" % data) show = TVShow(**data) existing_qualities = session.query(TVShow).filter(TVShow.name==show.name).\ filter(TVShow.season==show.season).\ filter(TVShow.episode==show.episode) preferred_qualities = existing_qualities.\ filter(TVShow.quality==preferred_quality) # nothing yet? then add unconditionally if existing_qualities.count()==0: session.add(show) log.info("ADDED %(name)s %(season)s %(episode)s in %(quality)s" % show.__dict__) # already in preferred quality? elif preferred_qualities.count() > 0: log.info("HAVE %(name)s %(season)s %(episode)s to %(quality)s" % show.__dict__) continue # update existing quality with this one: else: existing_quality = existing_qualities.one() if show.quality != existing_quality.quality: session.delete(existing_quality) session.add(show) log.info("UPDATED %(name)s %(season)s %(episode)s to %(quality)s" % show.__dict__) torrent_download_dir = path.expanduser(settings.get('main', 'torrent_download_dir')) shows = session.query(TVShow).filter(TVShow.status==u'new') if shows.count() > 0: log.info("downloading torrents to %s" % torrent_download_dir) for show in session.query(TVShow).filter(TVShow.status==u'new'): torrent_path, result = urlretrieve(show.torrent_url, path.join(torrent_download_dir, "%s.torrent" % show.filename)) if result.type == 'application/x-bittorrent': show.status = u'torrent_downloaded' log.info("DOWNLOAD %(name)s %(season)s %(episode)s in %(quality)s" % show.__dict__) else: log.error("Couldn't download %s" % show.torrent_url) else: log.info("no shows to download") session.commit()
class WebView(FlaskView): route_base = HOST def __init__(self, debug=False, host='0.0.0.0', port=5000): self.app = Flask(__name__, static_folder=os.path.join(os.getcwd(), ONG_FOLDER), static_url_path=os.path.join(HOST, ONG_FOLDER)) self.app_config() self.host = host self.port = port self.debug = debug self.session = Session() def app_config(self): self.app.config['MAX_CONTENT_LENGTH'] = 16 * 1024 * 1024 self.app.config["CACHE_TYPE"] = "null" @staticmethod def allowed_file(filename): return '.' in filename and filename.rsplit('.', 1)[1] in ALLOWED_EXTENSIONS @route('error') def error(self): return render_template("404.html", host=HOST), 404 @route('static/<path:path>') def static_file(self, path): if path.split("/")[0] not in ["images", "css", "js"]: return redirect(HOST + '/error') try: return send_file(path) except IOError: return redirect(HOST + '/error') @route('<ong>', methods=['GET', 'POST']) @route('<ong>/', methods=['GET', 'POST']) def upload_file(self, ong=None): o = Ong(session=self.session.get_session(), name=ong) if not o.load(): return redirect(HOST + '/error') if request.method == 'POST': fd = request.files['file1'] if fd and self.allowed_file(fd.filename): i = Image(session=self.session.get_session(), fd=fd, ong_name=ong) if i.save(): return render_template('response.html', msg="Imagem salva corretamente.", ong=o.get_name()) else: return render_template('response.html', msg="Falha ao salvar imagem.", ong=o.get_name()) return render_template('ong.html', host=HOST) @route('<ong>/cadastro', methods=['GET', 'POST']) def cadastre(self, ong): o = Ong(session=self.session.get_session(), name=ong) if not o.load(): return redirect(HOST + '/error') if request.method == 'POST': cnpj = request.form["cnpj"] coo = request.form["coo"] data = request.form["data"] total = request.form["total"] id_image = request.form["id_image"] meta = MetaImage(session=self.session.get_session(), id_image=id_image) meta.load() meta.cnpj = cnpj meta.coo = coo meta.data = data meta.total = total meta.status = "valid" meta.update() return redirect(os.path.join(HOST, o.get_name(), 'cadastro')) meta = MetaImage(session=self.session.get_session(), id_ong=o.get_id()) meta.search() if meta.id_image is None: return render_template('response.html', msg="Todas as imagens foram cadastradas!", ong=o.get_name(), host=HOST) i = Image(session=self.session.get_session(), id=meta.id_image) return render_template('cadastre.html', meta=meta, ong=o.get_name(), img=i, host=HOST) @route('<ong>/list') def list_images(self, ong=None): o = Ong(session=self.session.get_session(), name=ong) if not o.load(): return redirect(HOST + '/error') i = Image(session=self.session.get_session(), ong_name=ong) lst = i.search() return jsonify({'images': lst}) @route('<ong>/<path:path>') def get_ong_file(self, ong, path): return send_file(os.path.join(ONG_FOLDER, ong, path)) def start(self): self.register(self.app) self.app.run(host=self.host, port=self.port, debug=self.debug)