class PortofolioEntity extends AuditableEntity {

	public Order buy(SymbolEntity fromSymbol, double quantity, RateService rateService) throws OrderException {

		Objects.requireNonNull(fromSymbol, "fromSymbol must be not null");

		Preconditions.checkArgument(quantity > 0, "quantity must be positive: %s", getBaseCurrency());
		Preconditions.checkArgument(!getBaseCurrency().equals(fromSymbol), "Cannot buy baseCurrency: %s", getBaseCurrency());

		final SymbolEntity currency = getCurrencyFor(fromSymbol);

		Rate q = rateService.getLatest(fromSymbol.getCode(), currency.getCode());

		final BigDecimal currencyAmount;

		if (currency.equals(getBaseCurrency())) {
			currencyAmount = getAmount();
		} else if (getAsset(currency.getCode()) != null) {
			currencyAmount = getAsset(currency.getCode()).getQuantity();
		} else {
			currencyAmount = ZERO;
		}

		BigDecimal amountNeeded = q.getValue().multiply(BigDecimal.valueOf(quantity));

		if (currencyAmount.compareTo(amountNeeded) < 0) {
			throw OrderException.NOT_ENOUGH_FUND(fromSymbol.getCode(), quantity, currency.getCode(), currencyAmount.doubleValue(),
					amountNeeded.doubleValue());
		}

		AssetEntity ownedAsset = getAsset(fromSymbol.getCode());

		if (ownedAsset == null) {
			ownedAsset = new AssetEntity(this, fromSymbol, ZERO, currency, ZERO);
			assets.add(ownedAsset);
		}

		BigDecimal fundAfterPurchase = currencyAmount.subtract(amountNeeded);

		if (currency.equals(getBaseCurrency())) {
			this.amount = fundAfterPurchase;
		} else {
			AssetEntity currencyAsset = getAsset(currency.getCode());
			currencyAsset.withdraw(amountNeeded);
		}

		ownedAsset.makeDeposit(BigDecimal.valueOf(quantity), amountNeeded);

		return new Order(currency, amountNeeded.doubleValue(), fromSymbol, quantity);
	}

}