/**
* Copyright (c) 2015 The original author or authors
*
* 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.reveno.atp.acceptance.handlers;
import org.reveno.atp.acceptance.api.commands.CreateNewAccountCommand;
import org.reveno.atp.acceptance.api.commands.NewOrderCommand;
import org.reveno.atp.acceptance.api.transactions.AcceptOrder;
import org.reveno.atp.acceptance.api.transactions.CreateAccount;
import org.reveno.atp.acceptance.api.transactions.Credit;
import org.reveno.atp.acceptance.api.transactions.Debit;
import org.reveno.atp.acceptance.model.Account;
import org.reveno.atp.acceptance.model.Order;
import org.reveno.atp.acceptance.model.Position;
import org.reveno.atp.api.commands.CommandContext;
import java.util.Optional;
import java.util.stream.Stream;
import static java.lang.String.format;
public abstract class Commands {
public static Long createAccount(CreateNewAccountCommand cmd, CommandContext ctx) {
long accountId = ctx.id(Account.class);
ctx.executeTxAction(new CreateAccount(accountId, cmd.currency));
if (cmd.balance > 0)
ctx.executeTxAction(new Credit(accountId, cmd.balance, System.currentTimeMillis()));
return accountId;
}
public static void credit(Credit credit, CommandContext ctx) {
if (!ctx.repo().has(Account.class, credit.accountId))
throw new RuntimeException();
ctx.executeTxAction(credit);
}
public static void debit(Debit debit, CommandContext ctx) {
if (!ctx.repo().has(Account.class, debit.accountId))
throw new RuntimeException();
ctx.executeTxAction(debit);
}
public static Long newOrder(NewOrderCommand cmd, CommandContext ctx) {
long orderId = ctx.id(Order.class);
Account account = ctx.repo().get(Account.class, cmd.accountId);
if (cmd.positionId != null) {
long positionId = cmd.positionId;
require(account.positions().positions().containsKey(positionId), format("Can't find position %d in account %d", positionId, account.id()));
Position position = ctx.repo().get(Position.class, cmd.positionId);
long sum = position.sum() + account.orders().stream().map(oid -> ctx.repo().getO(Order.class, oid))
.flatMap(Commands::streamopt).filter(o -> o.positionId().isPresent() && o.positionId().get() == positionId)
.map(Order::size).reduce(0L, Long::sum);
require(sum != 0, format("The position %d is already filled.", positionId));
}
ctx.executeTxAction(new AcceptOrder(orderId, cmd.accountId, cmd.positionId, cmd.symbol, cmd.price, cmd.size, cmd.orderType));
return orderId;
}
static void require(boolean value, String message) {
if (!value)
throw new RuntimeException(message);
}
static <T> Stream<T> streamopt(Optional<T> opt) {
return opt.map(Stream::of).orElseGet(Stream::empty);
}
}