def notify_revenue(db): # beginning of last UTC day start_time = Delorean().last_day().truncate('day').datetime end_time = Delorean().truncate('day').datetime # This revenue calculating logic takes about 10s to run open_position_offset = positions.fast_position( db, end_time=start_time, ) open_position_trades = revenue_lib.open_position_trades( open_position_offset, db, start_time, ) trades = db\ .query(Trade)\ .join(Order)\ .filter(Order.actor == 'Multi')\ .filter(Trade.time_created >= start_time)\ .filter(Trade.time_created < end_time)\ .options(joinedload('order'))\ .order_by(Trade.time_created)\ .all() matched_trades, _ = revenue_lib.split_trades(open_position_trades + trades, ) __, revenue, __, __ = revenue_lib.profit_data(matched_trades, 'USD') slacker = Slacker('#general', 'revenue', icon_emoji=':moneybag:') slacker.notify('We made %s today' % revenue)
def test_profit_units_with_btc_fees(self): self.bid.fee = Money('0.01', 'BTC') matched_trades, position_trades = revenue_lib.split_trades(self.trades) profit_units = revenue_lib.profit_units(matched_trades) profit_units.should.have.length_of(1) profit_units[0]['profit'].should.equal(Money('-2.50', 'USD'))
def test_split_trades_partial_matches(self): self.ask.volume = Money('0.25', 'BTC') new_ask = Trade( Consts.ASK, Money('100', 'USD'), Money('0', 'USD'), Money('2', 'BTC'), '3', self.order, ) new_ask._exchange_rate = None self.trades.append(new_ask) matched_trades, position_trades = revenue_lib.split_trades(self.trades) # expect to match: # 0.25 of #1 with all of #2 # 0.75 of #1 with 0.75 of #3 # with 1.25 of #3 left in position matched_trades.should.have.length_of(4) matched_trades[0].volume.should.equal(Money('0.25', 'BTC')) matched_trades[1].volume.should.equal(Money('0.25', 'BTC')) matched_trades[2].volume.should.equal(Money('0.75', 'BTC')) matched_trades[3].volume.should.equal(Money('0.75', 'BTC')) position_trades.should.have.length_of(1) position_trades[0].volume.should.equal(Money('1.25', 'BTC'))
def test_split_trades(self): matched_trades, position_trades = revenue_lib.split_trades(self.trades) # Expect to match all of #1 with #2 with no remaining position. matched_trades.should.have.length_of(2) matched_trades[0].volume.should.equal(Money('1', 'BTC')) matched_trades[1].volume.should.equal(Money('1', 'BTC')) position_trades.should.be.empty
def test_split_trades_with_btc_fees(self): self.bid.fee = Money('0.01', 'BTC') matched_trades, position_trades = revenue_lib.split_trades(self.trades) # expect to match all of #1 with #2 # with no remaining position matched_trades.should.have.length_of(2) matched_trades[0].volume.should.equal(Money('1', 'BTC')) matched_trades[1].volume.should.equal(Money('1', 'BTC')) position_trades.should.be.empty
def generate_data(self): start_time, end_time = self.get_start_time_and_end_time() start_end_delta = end_time - start_time trades, fundamental_value, open_position_trades, open_position_offset = self.get_trades_and_fundamental_value(self.strategy_actor, start_time, end_time) trade_data, total_volume, daily_volumes, total_position, position_series = self.basic_trade_analysis(self.strategy_actor, trades, start_end_delta, open_position_offset, start_time) matched_trades, position_trades = revenue_lib.split_trades( open_position_trades + trades, volume_currency=self.volume_currency, ) profit, revenue, matched_fees, matched_volume_currency_fees, open_pl, open_position = self.get_current_trading_result( matched_trades, position_trades, self.price_currency, fundamental_value, ) revenue_series = self.get_revenue_series( matched_trades, start_time, ) template_args = { 'price_currency': self.price_currency, 'volume_currency': self.volume_currency, 'trade_data': trade_data, 'revenue_series': revenue_series, 'position_series': position_series, 'display_name': self.display_name, 'profit': profit, 'open_position': open_position, 'open_pl': open_pl, 'volume': total_volume, 'matched_fees': matched_fees, 'matched_volume_currency_fees': matched_volume_currency_fees, 'revenue': revenue, 'start_end_delta': start_end_delta, 'start_timestamp': Delorean(start_time, "UTC").epoch * 1000, 'end_timestamp': Delorean(end_time, "UTC").epoch * 1000, 'now_timestamp': Delorean().epoch * 1000, 'base_point_radius': float(self.base_point_radius), 'position_graph_min': float(self.position_graph_min), 'position_graph_max': float(self.position_graph_max), } return template_args
def test_profit_with_btc_and_fiat_fees_and_cad(self): self.bid.volume = Money('1', 'BTC') self.bid.price = Money('100', 'CAD') self.bid.fee = Money('0.01', 'BTC') self.ask.volume = Money('1', 'BTC') self.ask.price = Money('101', 'CAD') self.ask.fee = Money('1', 'CAD') self.order.fundamental_value = Money(250, 'CAD') matched_trades, position_trades = revenue_lib.split_trades(self.trades) p = revenue_lib.realized_pl(matched_trades) p.should.equal(Money('-2.50', 'CAD'))
def test_profit_units_with_btc_and_fiat_fees_and_cad(self): self.bid.volume = Money('1', 'BTC') self.bid.price = Money('100', 'CAD') self.bid.fee = Money('0.01', 'BTC') self.ask.volume = Money('1', 'BTC') self.ask.price = Money('101', 'CAD') self.ask.fee = Money('1', 'CAD') self.order.fundamental_value = Money(250, 'CAD') matched_trades, position_trades = revenue_lib.split_trades(self.trades) profit_units = revenue_lib.profit_units(matched_trades) profit_units.should.have.length_of(1) profit_units[0]['profit'].should.equal(Money('-2.50', 'CAD'))
def revenue_fees_profit_in_period(db, start_time, end_time): """ This function is an easy interface to getting revenue, fees, and profit, using the identical flow of functions that pentecost presently uses for the trading dashboard. This is unused at present but is added here for reference and for verifying the fast_(revenue|profit) functions below. """ trades = db\ .query(Trade)\ .join(Order)\ .filter(Order.actor == "Multi")\ .filter(Trade.time_created >= start_time)\ .filter(Trade.time_created < end_time)\ .options(joinedload('order').joinedload('datums'))\ .all() trades.sort(key=attrgetter('time_created')) # Get the system position up until the starting point of our graph. open_position_offset = positions.fast_position( db, end_time=start_time, ) position_trades = revenue_lib.open_position_trades( open_position_offset, db, start_time, ) matched_trades, _ = revenue_lib.split_trades( position_trades + trades, ) profit, revenue, fees, _ = revenue_lib.profit_data(matched_trades) return revenue, fees, profit
def check_profit(db): # beginning of current UTC day start_time = Delorean().truncate('day').datetime # This profit calculating logic takes about 10s to run open_position_offset = positions.fast_position( db, end_time=start_time, ) open_position_trades = revenue_lib.open_position_trades( open_position_offset, db, start_time, ) trades = db\ .query(Trade)\ .join(Order)\ .filter(Order.actor == 'Multi')\ .filter(Trade.time_created >= start_time)\ .options(joinedload('order'))\ .order_by(Trade.time_created)\ .all() matched_trades, _ = revenue_lib.split_trades(open_position_trades + trades, ) daily_pl = revenue_lib.realized_pl(matched_trades, 'USD') logger.info('Daily Profit to date: %s' % daily_pl) if daily_pl > DAILY_PROFIT_THRESHOLD: succeed('PROFIT') else: fail('PROFIT')
def test_profit_units(self): self.bid.price = Money('90', 'USD') matched_trades, position_trades = revenue_lib.split_trades(self.trades) profit_units = revenue_lib.profit_units(matched_trades) profit_units.should.have.length_of(1) profit_units[0]['profit'].should.equal(Money('10', 'USD'))