/** * Copyright 2010 Archfirst * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.archfirst.bfoms.domain.account.brokerage; import java.util.ArrayList; import java.util.List; import java.util.Set; import java.util.TreeSet; import javax.inject.Inject; import javax.persistence.criteria.CriteriaBuilder; import javax.persistence.criteria.CriteriaQuery; import javax.persistence.criteria.JoinType; import javax.persistence.criteria.Path; import javax.persistence.criteria.Predicate; import javax.persistence.criteria.Root; import org.archfirst.bfoms.domain.account.brokerage.order.Order; import org.archfirst.bfoms.domain.account.brokerage.order.Order_; import org.archfirst.bfoms.domain.account.brokerage.order.OrderCriteria; import org.archfirst.bfoms.domain.account.brokerage.order.OrderCriteriaInternal; import org.archfirst.bfoms.domain.account.brokerage.order.OrderEventPublisher; import org.archfirst.bfoms.domain.account.brokerage.order.OrderSide; import org.archfirst.bfoms.domain.account.brokerage.order.OrderStatus; import org.archfirst.bfoms.domain.security.User; import org.archfirst.common.domain.BaseRepository; import org.archfirst.common.quantity.DecimalQuantity; /** * BrokerageAccountRepository * * @author Naresh Bhatia */ public class BrokerageAccountRepository extends BaseRepository { @Inject private OrderEventPublisher orderEventPublisher; // ----- BrokerageAccount Methods ----- public BrokerageAccount findAccount(Long id) { BrokerageAccount account = entityManager.find(BrokerageAccount.class, id); if (account != null) { this.injectDependencies(account); } return account; } public List<BrokerageAccount> findAccountsWithPermission( User user, BrokerageAccountPermission permission) { @SuppressWarnings("unchecked") List<BrokerageAccount> accounts = entityManager.createQuery( "select ace.target from BrokerageAccountAce ace " + "where ace.recipient = :recipient " + "and ace.permission = :permission") .setParameter("recipient", user) .setParameter("permission", permission) .getResultList(); this.injectDependencies(accounts); return accounts; } public List<BrokerageAccountPermission> findPermissionsForAccount( User user, BrokerageAccount account) { @SuppressWarnings("unchecked") List<BrokerageAccountPermission> permissions = entityManager.createQuery( "select ace.permission from BrokerageAccountAce ace " + "where ace.recipient = :recipient " + "and ace.target = :target") .setParameter("recipient", user) .setParameter("target", account) .getResultList(); return permissions; } public BrokerageAccount findAccountForOrder(Long orderId) { BrokerageAccount account = (BrokerageAccount)entityManager.createQuery( "select a from BrokerageAccount a " + "join a.orders o " + "where o.id = :id") .setParameter("id", orderId) .getSingleResult(); if (account != null) { this.injectDependencies(account); } return account; } // ----- Order Methods ----- public Order findOrder(Long orderId) { return entityManager.find(Order.class, orderId); } @SuppressWarnings("unchecked") public List<Order> findOrders(OrderCriteriaInternal criteria) { // TODO: Modify this query to return executions in ascending order of id CriteriaBuilder builder = entityManager.getCriteriaBuilder(); CriteriaQuery<Order> query = builder.createQuery(Order.class); // select * from Order Root<Order> _order = query.from(Order.class); // Eager fetch executions (because executions are often needed along with orders) _order.fetch(Order_.executions, JoinType.LEFT); // Construct a predicate for the where clause using conjunction Predicate predicate = builder.conjunction(); // accountIds if (!criteria.getAccountIds().isEmpty()) { Path<BrokerageAccount> _account = _order.get(Order_.account); Path<Long> _accountId = _account.get(BrokerageAccount_.id); CriteriaBuilder.In<Long> inExpr = builder.in(_accountId); for (Long accountId : criteria.getAccountIds()) { inExpr = inExpr.value(accountId); } predicate = builder.and(predicate, inExpr); } // symbol if (criteria.getSymbol() != null) { predicate = builder.and( predicate, builder.equal(_order.get(Order_.symbol), criteria.getSymbol())); } // orderId if (criteria.getOrderId() != null) { predicate = builder.and( predicate, builder.equal(_order.get(Order_.id), criteria.getOrderId())); } // fromDate if (criteria.getFromDate() != null) { predicate = builder.and( predicate, builder.greaterThanOrEqualTo( _order.get(Order_.creationTime), criteria.getFromDate().toDateTimeAtStartOfDay())); } if (criteria.getToDate() != null) { predicate = builder.and( predicate, builder.lessThan( _order.get(Order_.creationTime), criteria.getToDate().plusDays(1).toDateTimeAtStartOfDay())); } if (!criteria.getSides().isEmpty()) { CriteriaBuilder.In<OrderSide> inExpr = builder.in(_order.get(Order_.side)); for (OrderSide side : criteria.getSides()) { inExpr = inExpr.value(side); } predicate = builder.and(predicate, inExpr); } if (!criteria.getStatuses().isEmpty()) { CriteriaBuilder.In<OrderStatus> inExpr = builder.in(_order.get(Order_.status)); for (OrderStatus status : criteria.getStatuses()) { inExpr = inExpr.value(status); } predicate = builder.and(predicate, inExpr); } // Assign predicate to where clause query.where(predicate); // Execute the query List<Order> orders = entityManager.createQuery(query).getResultList(); // Orders with multiple executions will be added to the above list multiple times // Filter out duplicates Set<Order> distinctOrderSet = new TreeSet<Order>(orders); List<Order> distinctOrderList = new ArrayList<Order>(distinctOrderSet); return distinctOrderList; } public List<Order> findOrders(OrderCriteria criteria) { List<Long> accountIds = new ArrayList<Long>(); accountIds.add(criteria.getAccountId()); OrderCriteriaInternal criteriaInternal = new OrderCriteriaInternal(criteria, accountIds); return this.findOrders(criteriaInternal); } public List<Order> findActiveBuyOrders(BrokerageAccount account) { OrderCriteria criteria = new OrderCriteria(); criteria.setAccountId(account.getId()); List<OrderSide> sides = new ArrayList<OrderSide>(); sides.add(OrderSide.Buy); criteria.setSides(sides); List<OrderStatus> statuses = new ArrayList<OrderStatus>(); statuses.add(OrderStatus.New); statuses.add(OrderStatus.PartiallyFilled); statuses.add(OrderStatus.PendingNew); statuses.add(OrderStatus.PendingCancel); criteria.setStatuses(statuses); return findOrders(criteria); } public List<Order> findActiveSellOrders( BrokerageAccount account, String symbol) { OrderCriteria criteria = new OrderCriteria(); criteria.setAccountId(account.getId()); criteria.setSymbol(symbol); List<OrderSide> sides = new ArrayList<OrderSide>(); sides.add(OrderSide.Sell); criteria.setSides(sides); List<OrderStatus> statuses = new ArrayList<OrderStatus>(); statuses.add(OrderStatus.New); statuses.add(OrderStatus.PartiallyFilled); statuses.add(OrderStatus.PendingNew); statuses.add(OrderStatus.PendingCancel); criteria.setStatuses(statuses); return findOrders(criteria); } public void refreshOrders(List<Order> orders) { for (Order order : orders) { entityManager.refresh(order); } } // ----- Lot Methods ----- public List<Lot> findActiveLots(BrokerageAccount account, String symbol) { @SuppressWarnings("unchecked") List<Lot> lots = entityManager.createQuery( "select l from Lot l " + "join l.account a " + "where a = :account " + "and l.symbol = :symbol " + "and l.quantity <> 0 " + "order by l.creationTime") .setParameter("account", account) .setParameter("symbol", symbol) .getResultList(); return lots; } public List<Lot> findActiveLots(BrokerageAccount account) { @SuppressWarnings("unchecked") List<Lot> lots = entityManager.createQuery( "select l from Lot l " + "join l.account a " + "where a = :account " + "and l.quantity <> 0 " + "order by l.symbol, l.creationTime") .setParameter("account", account) .getResultList(); return lots; } public DecimalQuantity getNumberOfShares( BrokerageAccount account, String symbol) { DecimalQuantity numberOfShares = DecimalQuantity.ZERO; List<Lot> lots = findActiveLots(account, symbol); for (Lot lot : lots) { numberOfShares = numberOfShares.plus(lot.getQuantity()); } return numberOfShares; } // ----- Helper Methods ----- public void injectDependencies(List<BrokerageAccount> accounts) { for (BrokerageAccount account : accounts) { account.setBrokerageAccountRepository(this); } } public void injectDependencies(BrokerageAccount account) { account.setBrokerageAccountRepository(this); account.setOrderEventPublisher(orderEventPublisher); } }