implement scorer
This commit is contained in:
45
core/src/main/java/ru/trader/analysis/FilteredMarket.java
Normal file
45
core/src/main/java/ru/trader/analysis/FilteredMarket.java
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
package ru.trader.analysis;
|
||||||
|
|
||||||
|
import ru.trader.core.*;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
public class FilteredMarket {
|
||||||
|
private final Market market;
|
||||||
|
private final MarketFilter filter;
|
||||||
|
|
||||||
|
public FilteredMarket(Market market, MarketFilter filter) {
|
||||||
|
this.market = market;
|
||||||
|
this.filter = filter;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Stream<Place> get(){
|
||||||
|
return market.get().stream()
|
||||||
|
.filter(p -> !filter.isFiltered(p));
|
||||||
|
}
|
||||||
|
|
||||||
|
public Stream<Vendor> getVendors(){
|
||||||
|
return get().flatMap(p -> p.get().stream())
|
||||||
|
.filter(v -> !filter.isFiltered(v));
|
||||||
|
}
|
||||||
|
|
||||||
|
public Collection<Item> getItems(){
|
||||||
|
return market.getItems();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Stream<Offer> getSell(Item item){
|
||||||
|
return getOffers(OFFER_TYPE.SELL, item);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Stream<Offer> getBuy(Item item){
|
||||||
|
return getOffers(OFFER_TYPE.BUY, item);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Stream<Offer> getOffers(OFFER_TYPE offerType, Item item){
|
||||||
|
return market.getStat(offerType, item).getOffers().stream()
|
||||||
|
.filter(o -> !filter.isFiltered(o.getVendor(), true));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
102
core/src/main/java/ru/trader/analysis/Scorer.java
Normal file
102
core/src/main/java/ru/trader/analysis/Scorer.java
Normal file
@@ -0,0 +1,102 @@
|
|||||||
|
package ru.trader.analysis;
|
||||||
|
|
||||||
|
import ru.trader.core.*;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
public class Scorer {
|
||||||
|
private final Map<Item, Offer> sellOffers;
|
||||||
|
private final Map<Item, Offer> buyOffers;
|
||||||
|
private final FilteredMarket market;
|
||||||
|
private final Profile profile;
|
||||||
|
|
||||||
|
private int ordersCount = 5;
|
||||||
|
|
||||||
|
private double avgProfit;
|
||||||
|
|
||||||
|
public Scorer(FilteredMarket market, Profile profile) {
|
||||||
|
this.market = market;
|
||||||
|
this.profile = profile;
|
||||||
|
sellOffers = new HashMap<>(100, 0.9f);
|
||||||
|
buyOffers = new HashMap<>(100, 0.9f);
|
||||||
|
market.getItems().parallelStream().forEach(this::fillOffers);
|
||||||
|
avgProfit = computeAvgProfit();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void fillOffers(Item item){
|
||||||
|
Optional<Offer> offer = market.getSell(item).findFirst();
|
||||||
|
if (offer.isPresent()){
|
||||||
|
sellOffers.put(item, offer.get());
|
||||||
|
}
|
||||||
|
offer = market.getBuy(item).findFirst();
|
||||||
|
if (offer.isPresent()){
|
||||||
|
buyOffers.put(item, offer.get());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setOrdersCount(int ordersCount) {
|
||||||
|
this.ordersCount = ordersCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
private double computeAvgProfit(){
|
||||||
|
OptionalDouble avg = sellOffers.values().stream()
|
||||||
|
.flatMap(this::mapToOrder)
|
||||||
|
.mapToDouble(Order::getProfit)
|
||||||
|
.average();
|
||||||
|
return avg.orElse(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Score getScore(Vendor vendor){
|
||||||
|
Stream<Order> sellOrders = vendor.getAllSellOffers().stream().flatMap(this::mapToOrder);
|
||||||
|
Stream<Order> buyOrders = vendor.getAllBuyOffers().stream().flatMap(this::mapToOrder);
|
||||||
|
return new Score(sellOrders, buyOrders);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Stream<Order> mapToOrder(Offer offer) {
|
||||||
|
Offer sell;
|
||||||
|
Offer buy;
|
||||||
|
if (offer.getType() == OFFER_TYPE.SELL){
|
||||||
|
sell = offer;
|
||||||
|
buy = buyOffers.get(offer.getItem());
|
||||||
|
} else {
|
||||||
|
sell = sellOffers.get(offer.getItem());
|
||||||
|
buy = offer;
|
||||||
|
}
|
||||||
|
if (sell == null || buy == null) return Stream.empty();
|
||||||
|
Order order = new Order(sell, buy, profile.getBalance(), profile.getShip().getCargo());
|
||||||
|
if (order.getProfit() <= 0) return Stream.empty();
|
||||||
|
return Stream.of(order);
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Score {
|
||||||
|
private double sellProfit;
|
||||||
|
private double buyProfit;
|
||||||
|
private double score;
|
||||||
|
|
||||||
|
public Score(Stream<Order> sell, Stream<Order> buy) {
|
||||||
|
sellProfit = computeProfits(sell);
|
||||||
|
buyProfit = computeProfits(buy);
|
||||||
|
|
||||||
|
long count = sell.limit(ordersCount).count();
|
||||||
|
computeScore(count);
|
||||||
|
}
|
||||||
|
|
||||||
|
private double computeProfits(Stream<Order> orders) {
|
||||||
|
OptionalDouble profit = orders.sorted(Comparator.<Order>reverseOrder())
|
||||||
|
.limit(ordersCount)
|
||||||
|
.mapToDouble(Order::getProfit)
|
||||||
|
.average();
|
||||||
|
return profit.orElse(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void computeScore(long sellOrdersCount){
|
||||||
|
score = (sellProfit + buyProfit)/2;
|
||||||
|
if (sellOrdersCount < ordersCount){
|
||||||
|
score =- Math.abs(avgProfit-sellProfit) * (ordersCount - sellOrdersCount) / score;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -84,6 +84,11 @@ public class MarketFilter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public boolean isFiltered(Vendor vendor){
|
public boolean isFiltered(Vendor vendor){
|
||||||
|
return isFiltered(vendor, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isFiltered(Vendor vendor, boolean checkPlace){
|
||||||
|
if (checkPlace && isFiltered(vendor.getPlace())) return true;
|
||||||
if (distance > 0 && vendor.getDistance() > distance) return true;
|
if (distance > 0 && vendor.getDistance() > distance) return true;
|
||||||
if (excludes.contains(vendor)) return true;
|
if (excludes.contains(vendor)) return true;
|
||||||
for (SERVICE_TYPE service : services) {
|
for (SERVICE_TYPE service : services) {
|
||||||
|
|||||||
@@ -16,9 +16,13 @@ public class Order implements Comparable<Order> {
|
|||||||
this.profit = Double.NaN;
|
this.profit = Double.NaN;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Order(Offer sell, Offer buy, double balance, long limit) {
|
||||||
|
this(sell, buy);
|
||||||
|
setMax(balance, limit);
|
||||||
|
}
|
||||||
|
|
||||||
public Order(Offer sell, Offer buy, long count) {
|
public Order(Offer sell, Offer buy, long count) {
|
||||||
this.sell = sell;
|
this(sell, buy);
|
||||||
this.buy = buy;
|
|
||||||
this.count = getMaxCount(sell, buy, count);
|
this.count = getMaxCount(sell, buy, count);
|
||||||
this.profit = (buy.getPrice() - sell.getPrice()) * count;
|
this.profit = (buy.getPrice() - sell.getPrice()) * count;
|
||||||
}
|
}
|
||||||
|
|||||||
15
core/src/main/java/ru/trader/core/Profile.java
Normal file
15
core/src/main/java/ru/trader/core/Profile.java
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
package ru.trader.core;
|
||||||
|
|
||||||
|
public class Profile {
|
||||||
|
|
||||||
|
private double balance;
|
||||||
|
private Ship ship;
|
||||||
|
|
||||||
|
public double getBalance() {
|
||||||
|
return balance;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Ship getShip() {
|
||||||
|
return ship;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,35 +2,23 @@ package ru.trader.core;
|
|||||||
|
|
||||||
public class Ship {
|
public class Ship {
|
||||||
|
|
||||||
private double balance;
|
private int cargo;
|
||||||
private long cargo;
|
|
||||||
private double engine;
|
private double engine;
|
||||||
private int jumps;
|
|
||||||
|
|
||||||
public Ship(double balance, long cargo, double engine, int jumps) {
|
public Ship(int cargo, double engine) {
|
||||||
this.balance = balance;
|
|
||||||
this.cargo = cargo;
|
this.cargo = cargo;
|
||||||
this.engine = engine;
|
this.engine = engine;
|
||||||
this.jumps = jumps;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Ship copyOf(Ship other){
|
public static Ship copyOf(Ship other){
|
||||||
return new Ship(other.balance, other.cargo, other.engine, other.jumps);
|
return new Ship(other.cargo, other.engine);
|
||||||
}
|
}
|
||||||
|
|
||||||
public double getBalance() {
|
public int getCargo() {
|
||||||
return balance;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setBalance(double balance) {
|
|
||||||
this.balance = balance;
|
|
||||||
}
|
|
||||||
|
|
||||||
public long getCargo() {
|
|
||||||
return cargo;
|
return cargo;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setCargo(long cargo) {
|
public void setCargo(int cargo) {
|
||||||
this.cargo = cargo;
|
this.cargo = cargo;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -42,11 +30,4 @@ public class Ship {
|
|||||||
this.engine = engine;
|
this.engine = engine;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getJumps() {
|
|
||||||
return jumps;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setJumps(int jumps) {
|
|
||||||
this.jumps = jumps;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,6 +13,12 @@ public class VendorsIterator implements Iterator<Vendor> {
|
|||||||
private Iterator<Vendor> vendors;
|
private Iterator<Vendor> vendors;
|
||||||
private Vendor next;
|
private Vendor next;
|
||||||
|
|
||||||
|
public VendorsIterator(Iterator<Place> places, boolean includeTransit) {
|
||||||
|
this.places = places;
|
||||||
|
this.includeTransit = includeTransit;
|
||||||
|
nextPlace();
|
||||||
|
}
|
||||||
|
|
||||||
public VendorsIterator(Collection<Place> places, boolean includeTransit) {
|
public VendorsIterator(Collection<Place> places, boolean includeTransit) {
|
||||||
this.places = places.iterator();
|
this.places = places.iterator();
|
||||||
this.includeTransit = includeTransit;
|
this.includeTransit = includeTransit;
|
||||||
|
|||||||
1
core/src/test/resources/test3.xml
Normal file
1
core/src/test/resources/test3.xml
Normal file
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user