示例#1
0
 def test_window_frame_repr(self):
     self.assertEqual(
         repr(RowRange(start=-1)),
         '<RowRange: ROWS BETWEEN 1 PRECEDING AND UNBOUNDED FOLLOWING>')
     self.assertEqual(
         repr(ValueRange(start=None, end=1)),
         '<ValueRange: RANGE BETWEEN UNBOUNDED PRECEDING AND 1 FOLLOWING>')
     self.assertEqual(
         repr(ValueRange(start=0, end=0)),
         '<ValueRange: RANGE BETWEEN CURRENT ROW AND CURRENT ROW>')
     self.assertEqual(
         repr(RowRange(start=0, end=0)),
         '<RowRange: ROWS BETWEEN CURRENT ROW AND CURRENT ROW>')
示例#2
0
 def test_invalid_type_end_row_range(self):
     msg = "end argument must be a positive integer, zero, or None, but got 'a'."
     with self.assertRaisesMessage(ValueError, msg):
         list(Employee.objects.annotate(test=Window(
             expression=Sum('salary'),
             frame=RowRange(end='a'),
         )))
示例#3
0
 def test_row_range_rank(self):
     """
     A query with ROWS BETWEEN UNBOUNDED PRECEDING AND 3 FOLLOWING.
     The resulting sum is the sum of the three next (if they exist) and all
     previous rows according to the ordering clause.
     """
     qs = Employee.objects.annotate(sum=Window(
         expression=Sum('salary'),
         order_by=[F('hire_date').asc(), F('name').desc()],
         frame=RowRange(start=None, end=3),
     )).order_by('sum', 'hire_date')
     self.assertIn('ROWS BETWEEN UNBOUNDED PRECEDING AND 3 FOLLOWING', str(qs.query))
     self.assertQuerysetEqual(qs, [
         ('Miller', 100000, 'Management', datetime.date(2005, 6, 1), 280000),
         ('Johnson', 80000, 'Management', datetime.date(2005, 7, 1), 325000),
         ('Jones', 45000, 'Accounting', datetime.date(2005, 11, 1), 362000),
         ('Smith', 55000, 'Sales', datetime.date(2007, 6, 1), 415000),
         ('Jenson', 45000, 'Accounting', datetime.date(2008, 4, 1), 453000),
         ('Williams', 37000, 'Accounting', datetime.date(2009, 6, 1), 513000),
         ('Brown', 53000, 'Sales', datetime.date(2009, 9, 1), 553000),
         ('Smith', 38000, 'Marketing', datetime.date(2009, 10, 1), 603000),
         ('Wilkinson', 60000, 'IT', datetime.date(2011, 3, 1), 637000),
         ('Johnson', 40000, 'Marketing', datetime.date(2012, 3, 1), 637000),
         ('Adams', 50000, 'Accounting', datetime.date(2013, 7, 1), 637000),
         ('Moore', 34000, 'IT', datetime.date(2013, 8, 1), 637000),
     ], transform=lambda row: (row.name, row.salary, row.department, row.hire_date, row.sum))
示例#4
0
 def test_subquery_row_range_rank(self):
     qs = Employee.objects.annotate(
         highest_avg_salary_date=Subquery(
             Employee.objects.filter(
                 department=OuterRef('department'),
             ).annotate(
                 avg_salary=Window(
                     expression=Avg('salary'),
                     order_by=[F('hire_date').asc()],
                     frame=RowRange(start=-1, end=1),
                 ),
             ).order_by('-avg_salary', 'hire_date').values('hire_date')[:1],
         ),
     ).order_by('department', 'name')
     self.assertQuerysetEqual(qs, [
         ('Adams', 'Accounting', datetime.date(2005, 11, 1)),
         ('Jenson', 'Accounting', datetime.date(2005, 11, 1)),
         ('Jones', 'Accounting', datetime.date(2005, 11, 1)),
         ('Williams', 'Accounting', datetime.date(2005, 11, 1)),
         ('Moore', 'IT', datetime.date(2011, 3, 1)),
         ('Wilkinson', 'IT', datetime.date(2011, 3, 1)),
         ('Johnson', 'Management', datetime.date(2005, 6, 1)),
         ('Miller', 'Management', datetime.date(2005, 6, 1)),
         ('Johnson', 'Marketing', datetime.date(2009, 10, 1)),
         ('Smith', 'Marketing', datetime.date(2009, 10, 1)),
         ('Brown', 'Sales', datetime.date(2007, 6, 1)),
         ('Smith', 'Sales', datetime.date(2007, 6, 1)),
     ], transform=lambda row: (row.name, row.department, row.highest_avg_salary_date))
示例#5
0
 def test_invalid_type_start_row_range(self):
     msg = "start argument must be a negative integer, zero, or None, but got 'a'."
     with self.assertRaisesMessage(ValueError, msg):
         list(Employee.objects.annotate(test=Window(
             expression=Sum('salary'),
             order_by=F('hire_date').asc(),
             frame=RowRange(start='a'),
         )))
示例#6
0
 def get_all_deposits(self, running_totals=False):
     """
     :return: a list of (date, amt, total) tuples
     """
     if not self:
         return []
     if running_totals:
         return self.deposits().annotate(
             cum_total=Window(expression=Sum('net_amount'),
                              order_by=F('trade_date').asc(),
                              frame=RowRange(end=0))).values_list(
                                  'trade_date', 'cum_total')
     else:
         return self.deposits().values_list(
             'trade_date',
             F('net_amount') * F('account__joint_share'))
def newest_books_by_author(request):
    """
    Try emulating the following query:
        select
            id,
            title,
            published,
            author_id,
            last_value(id) over (
                partition by author_id
                order by published
                range between unbounded preceding and unbounded following
            ) last
        from books_book
        order by author_id, published;
    """
    books = Book.objects.annotate(last_id=Window(
        expression=LastValue('id'),
        partition_by=F('author_id'),
        order_by=F('published'),
        frame=RowRange(start=None, end=None),
    ))

    return render(request, 'books/newest.html', {'books': books})
示例#8
0
def moving_average_strategy(user):
    """Initialise moving average strategy."""
    strategies = Strategy.objects.filter(user=user).active()

    if not strategies.exists():
        return

    strategy_symbols = list(strategies.values_list("asset__symbol", flat=True))

    # Update latest bars
    update_bars(strategy_symbols, "15Min", limit=1)

    api = TradeApiRest()
    for strategy in strategies:
        total_bars_count = fetch_bar_data_for_strategy(strategy)
        if not total_bars_count:
            logger.info(
                f"Insufficient bar data for asset: {strategy.asset.id}")
            continue

        # Calculate moving average and conditionally place order
        annotated_bars = Bar.objects.filter(
            asset_id=strategy.asset.id).annotate(moving_average=Window(
                expression=Avg("c"),
                order_by=F("t").desc(),
                frame=RowRange(start=0, end=int(total_bars_count - 1)),
            ), )

        latest_bar = annotated_bars.first()
        previous_bar = annotated_bars[1]
        symbol = strategy.asset.symbol
        if (latest_bar.c >= latest_bar.moving_average
                and previous_bar.c < previous_bar.moving_average):
            side = Order.BUY
            account = api.account_info()
            trade_value = min(float(strategy.trade_value),
                              float(account.__dict__["_raw"]["equity"]))
        elif (latest_bar.c <= latest_bar.moving_average
              and previous_bar.c > previous_bar.moving_average):
            side = Order.SELL

            try:
                position = api.list_position_by_symbol(symbol)
            except APIError:
                logger.info(
                    f"No position exists, unable to sell: {strategy.asset.id}")
                continue
            else:
                if position.__dict__["_raw"]["side"] == "short":
                    logger.info(
                        f"Asset is long, unable to sell: {strategy.asset.id}")
                    continue

            trade_value = min(
                float(strategy.trade_value),
                float(position.__dict__["_raw"]["market_value"]),
            )
        else:
            # No order required with current quote
            logger.info(
                f"No order placed. symbol, close price, moving average {symbol}, {latest_bar.c}, {latest_bar.moving_average}"
            )
            continue

        try:
            order = api.submit_order(
                symbol=symbol,
                notional=trade_value,
                side=side,
                type=Order.MARKET,
                time_in_force=Order.GTC,
            )
            logger.info(
                f"Order placed. symbol, side, close, moving_average: {symbol}, {side}, {latest_bar.c}, {latest_bar.moving_average}"
            )
        except Exception as e:
            logger.warning(f"Tradeview order failed: {e}")
            return

        raw_order = order.__dict__["_raw"]
        order = Order.objects.create(
            user=user,
            id=raw_order.get("id"),
            client_order_id=raw_order.get("client_order_id"),
            created_at=raw_order.get("created_at"),
            updated_at=raw_order.get("updated_at"),
            submitted_at=raw_order.get("submitted_at"),
            filled_at=raw_order.get("filled_at"),
            expired_at=raw_order.get("expired_at"),
            canceled_at=raw_order.get("canceled_at"),
            failed_at=raw_order.get("failed_at"),
            replaced_at=raw_order.get("replaced_at"),
            replaced_by=raw_order.get("replaced_by"),
            replaces=raw_order.get("replaces"),
            asset_id=strategy.asset,
            notional=raw_order.get("notional"),
            qty=raw_order.get("qty"),
            filled_qty=raw_order.get("filled_qty"),
            filled_avg_price=raw_order.get("filled_avg_price"),
            order_class=raw_order.get("order_class"),
            type=raw_order.get("type"),
            side=raw_order.get("side"),
            time_in_force=raw_order.get("time_in_force"),
            limit_price=raw_order.get("limit_price"),
            stop_price=raw_order.get("stop_price"),
            status=raw_order.get("status"),
            extended_hours=raw_order.get("extended_hours"),
            trail_percent=raw_order.get("trail_percent"),
            trail_price=raw_order.get("trail_price"),
            hwm=raw_order.get("hwm"),
        )
        legs = raw_order.get("legs")
        if legs:
            order.legs.set(legs)