package org.cryptocoinpartners.schema;
// import java.util.logging.Logger;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import javax.inject.Inject;
import javax.inject.Singleton;
import javax.persistence.Cacheable;
import javax.persistence.Entity;
import javax.persistence.Inheritance;
import javax.persistence.InheritanceType;
import javax.persistence.OneToOne;
import javax.persistence.Transient;
import org.cryptocoinpartners.enumeration.OrderState;
import org.cryptocoinpartners.enumeration.TransactionType;
import org.cryptocoinpartners.esper.annotation.When;
import org.cryptocoinpartners.module.Context;
import org.cryptocoinpartners.schema.dao.Dao;
import org.cryptocoinpartners.service.PortfolioService;
import org.cryptocoinpartners.service.QuoteService;
import org.cryptocoinpartners.util.Remainder;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* PortfolioManagers are allowed to control the Positions within a Portfolio
*
* @author Tim Olson
*/
@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@Singleton
@Cacheable
public class PortfolioManager extends EntityBase implements Context.AttachListener {
// private BasicPortfolioService portfolioService;
// todo we need to get the tradeable portfolio separately from the "reserved" portfolio (assets needed for open orders)
@OneToOne
public Portfolio getPortfolio() {
return portfolio;
}
public void setContext(Context context) {
this.context = context;
}
@Transient
public Context getContext() {
return context;
}
@Transient
public PortfolioService getPortfolioService() {
return portfolioService;
}
@When("@Priority(6) select * from OrderUpdate where state.open=true`")
private void updateReservation(OrderUpdate update) {
//removes the reservation from the transactions
Transaction reservation = update.getOrder().getReservation();
if (reservation != null && update.getState() != OrderState.NEW) {
if (reservation.getType() == (TransactionType.BUY_RESERVATION) || reservation.getType() == (TransactionType.SELL_RESERVATION)) {
Amount price = (update.getOrder().getLimitPrice() == null) ? ((update.getOrder().getVolume().isNegative()) ? quotes.getLastBidForMarket(
update.getOrder().getMarket()).getPrice() : quotes.getLastAskForMarket(update.getOrder().getMarket()).getPrice()) : update.getOrder()
.getLimitPrice();
Amount updateAmount = reservation.getType() == (TransactionType.BUY_RESERVATION) ? (update.getOrder().getUnfilledVolume().times(price,
Remainder.ROUND_EVEN)).negate() : update.getOrder().getVolume();
reservation.setAmount(updateAmount);
}
}
}
@When("@Priority(5) select * from OrderUpdate where state.open=false")
private void removeReservation(OrderUpdate update) {
//removes the reservation from the transactions
Order order = update.getOrder();
Transaction reservation = order.getReservation();
switch (update.getState()) {
case NEW:
break;
case TRIGGER:
break;
case ROUTED:
break;
case PLACED:
break;
case PARTFILLED:
break;
case FILLED:
if (order instanceof SpecificOrder)
portfolio.removeTransaction(reservation);
break;
case CANCELLING:
break;
case CANCELLED:
if (order instanceof SpecificOrder)
portfolio.removeTransaction(reservation);
break;
case REJECTED:
if (order instanceof SpecificOrder)
portfolio.removeTransaction(reservation);
break;
case EXPIRED:
if (order instanceof SpecificOrder)
portfolio.removeTransaction(reservation);
break;
default:
log.warn("Unknown order state: " + update.getState());
break;
}
}
private class handleTransactionRunnable implements Runnable {
private final Transaction transaction;
// protected Logger log;
public handleTransactionRunnable(Transaction transaction) {
this.transaction = transaction;
}
@Override
public void run() {
updatePortfolio(transaction);
}
}
private class handleFillRunnable implements Runnable {
private final Fill fill;
// protected Logger log;
public handleFillRunnable(Fill fill) {
this.fill = fill;
}
@Override
public void run() {
// fill.persit();
portfolio.modifyPosition(fill, new Authorization("Fill for " + fill.toString()));
}
}
// @When("@Priority(9) select * from Fill")
// public void handleFill(Fill fill) {
// service.submit(new handleFillRunnable(fill));
// }
// @When("@Priority(8) select * from Transaction where NOT (Transaction.type=TransactionType.BUY and Transaction.type=TransactionType.SELL)")
@When("@Priority(8) select * from Transaction")
public void handleTransaction(Transaction transaction) {
//
// updatePortfolio(transaction);
service.submit(new handleTransactionRunnable(transaction));
}
public void updatePortfolio(Transaction transaction) {
// PersistUtil.insert(transaction);
// Transaction tans = new Transaction(this, position.getExchange(), position.getAsset(), TransactionType.CREDIT, position.getVolume(),
// position.getAvgPrice());
//context.route(transaction);
log.info("transaction: " + transaction + " Recieved.");
if (transaction.getPortfolio().equals(portfolio)) {
Portfolio portfolio = transaction.getPortfolio();
Asset baseAsset = transaction.getCurrency();
Market market = transaction.getMarket();
Amount amount = transaction.getAmount();
TransactionType type = transaction.getType();
Amount price = transaction.getPrice();
Exchange exchange = transaction.getExchange();
// Add transaction to approraite portfolio
portfolio.addTransaction(transaction);
// portfolioService.
Position position;
// update postion
//if (type == TransactionType.BUY || type == TransactionType.SELL) {
//position = new Position(portfolio, exchange, market, baseAsset, amount, price);
//transaction.getFill();
//portfolio.modifyPosition(transaction.getFill(), new Authorization("Fill for " + transaction.toString()));
//} else if (type == TransactionType.REALISED_PROFIT_LOSS) {
//Transfer ammount to base currency
// neeed to be able to implment this on the exchange via orders
// if (!transaction.getCurrency().equals(transaction.getPortfolio().getBaseAsset())) {
// Listing tradedListing = Listing.forPair(transaction.getCurrency(), transaction.getPortfolio().getBaseAsset());
// //we will be selling transaction currency and buying base currency i.e. sell BTC, buy USD
// Offer tradedRate = quotes.getImpliedBestAskForListing(tradedListing);
//
// TransactionType type=(transaction.getAmount().isPositive()) ? TransactionType.CREDIT:TransactionType.DEBIT;
//
// Transaction initialDedit = new Transaction(transaction.getPortfolio(), transaction.getExchange(), transaction.getCurrency(),
// type, transaction.getAmount());
// context.route(initialDedit);
// initialDedit.persit();
//}
// }
log.info("transaction: " + transaction + " Proccessed.");
} else {
return;
}
}
@Override
public void afterAttach(Context context) {
context.attachInstance(getPortfolio());
context.attachInstance(getPortfolioService());
}
/** for subclasses */
protected PortfolioManager(String portfolioName) {
// new PortfolioManager();
// portfolio.setName(portfolioName);
// portfolio.setManager(this);
// this.portfolio = new Portfolio(portfolioName, this);
// portfolioService.getPortfolio().setName(portfolioName);
// portfolioService.getPortfolio().setManager(this);
// this.portfolioService = new BasicPortfolioService(portfolio);
}
public static class DataSubscriber {
private static final DateTimeFormatter FORMAT = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss");
@SuppressWarnings("rawtypes")
public void update(Long Timestamp, Portfolio portfolio) {
// PortfolioService portfolioService = context.
PortfolioService portfolioService = portfolio.context.getInjector().getInstance(PortfolioService.class);
// ..getManager().getPortfolioService();
//portfolio.getPositions();
log.info("Date: " + (Timestamp != null ? (FORMAT.print(Timestamp)) : "") + " Portfolio: " + portfolio + " Total Value (" + portfolio.getBaseAsset()
+ "):"
+ portfolioService.getBaseCashBalance(portfolio.getBaseAsset()).plus(portfolioService.getBaseUnrealisedPnL(portfolio.getBaseAsset()))
+ " (Cash Balance:" + portfolioService.getBaseCashBalance(portfolio.getBaseAsset()) + " Realised PnL (M2M):"
+ portfolioService.getBaseRealisedPnL(portfolio.getBaseAsset()) + " Open Trade Equity:"
+ portfolioService.getBaseUnrealisedPnL(portfolio.getBaseAsset()) + " MarketValue:"
+ portfolioService.getBaseMarketValue(portfolio.getBaseAsset()) + ")");
log.info(portfolio.getNetPositions().toString());
log.info(portfolio.getDetailedPositions().toString());
// Object itt = portfolio.getPositions().iterator();
// while (itt.hasNext()) {
// Position postion = itt.next();
// logger.info("Date: " + (Timestamp != null ? (FORMAT.print(Timestamp)) : "") + " Asset: " + postion.getAsset() + " Position: "
// + postion.getVolume());
// }
}
}
// JPA
protected PortfolioManager() {
// portfolio.setManager(this);
// portfolioService.setManager(this);
}
// @Inject
protected PortfolioManager(PortfolioService portfolioService) {
this.portfolioService = portfolioService;
}
// @Inject
protected void setPortfolio(Portfolio portfolio) {
this.portfolio = portfolio;
}
@Transient
protected void setPortfolioService(PortfolioService portfolioService) {
this.portfolioService = portfolioService;
}
protected static Logger log = LoggerFactory.getLogger("org.cryptocoinpartners.portfolioManager");
@Inject
protected transient Context context;
@Inject
protected QuoteService quotes;
@Inject
protected PortfolioService portfolioService;
protected Portfolio portfolio;
private static ExecutorService service = Executors.newFixedThreadPool(1);
@Override
public void persit() {
// TODO Auto-generated method stub
}
@Override
public void detach() {
// TODO Auto-generated method stub
}
@Override
public void merge() {
// TODO Auto-generated method stub
}
@Override
@Transient
public Dao getDao() {
// TODO Auto-generated method stub
return null;
}
@Override
public void delete() {
// TODO Auto-generated method stub
}
@Override
public EntityBase refresh() {
// TODO Auto-generated method stub
return null;
}
}