agents.firm.sales.prediction.RegressionSalePredictor.java Source code

Java tutorial

Introduction

Here is the source code for agents.firm.sales.prediction.RegressionSalePredictor.java

Source

/*
 * Copyright (c) 2014 by Ernesto Carrella
 * Licensed under MIT license. Basically do what you want with it but cite me and don't sue me. Which is just politeness, really.
 * See the file "LICENSE" for more information
 */

package agents.firm.sales.prediction;

import agents.firm.sales.SalesDepartment;
import com.google.common.base.Preconditions;
import financial.market.Market;
import model.MacroII;
import model.utilities.stats.collectors.PeriodicMarketObserver;
import model.utilities.stats.regression.LinearRegression;
import org.apache.commons.collections15.Transformer;

/**
 * <h4>Description</h4>
 * <p/> This object spawns a periodic market observer to look
 * <p/>
 * <p/>
 * <h4>Notes</h4>
 * Created with IntelliJ
 * <p/>
 * <p/>
 * <h4>References</h4>
 *
 * @author carrknight
 * @version 2013-07-11
 * @see
 */
public class RegressionSalePredictor extends BaseSalesPredictor {

    /**
     * the regression object we use
     */
    protected LinearRegression regression;

    /**
     * The object that periodically reads in stuff from the market
     */
    protected PeriodicMarketObserver observer;

    /**
     * The PeriodicMarketObserver is created straight into the constructor
     * @param market the market to observe
     * @param macroII a link to the model to schedule yourself
     */
    public RegressionSalePredictor(Market market, MacroII macroII) {

        this(new PeriodicMarketObserver(market, macroII));

    }

    /**
     * The PeriodicMarketObserver is created straight into the constructor
     * @param market the market to observe
     * @param macroII a link to the model to schedule yourself
     */
    public RegressionSalePredictor(Market market, MacroII macroII, float observationProbability) {

        this(new PeriodicMarketObserver(market, macroII, observationProbability));

    }

    /**
     * Give a premade observer to sale predictor. The observer will be turned Off when the predictor is turned off!
     * @param observer
     */
    public RegressionSalePredictor(PeriodicMarketObserver observer) {
        regression = new LinearRegression();

        this.observer = observer;
    }

    /**
     * Runs the regression and returns the regression prediction if it is possible or the last price otherwise.
     *
     *
     *
     * @param dept                   the sales department that has to answer this question
     * @param expectedProductionCost the HQ estimate of costs in producing whatever it wants to sell. It isn't necesarilly used.
     * @param increaseStep ignored
     * @return the best offer available/predicted or -1 if there are no quotes/good predictions
     */
    @Override
    public float predictSalePriceAfterIncreasingProduction(SalesDepartment dept, int expectedProductionCost,
            int increaseStep) {
        Preconditions.checkArgument(increaseStep >= 0);

        //regress and return
        updateModel();

        if (Double.isNaN(regression.getIntercept())) //if we couldn't do a regression, just return today's pricing
            return dept.hypotheticalSalePrice();
        else {
            //if you are producing more than what's sold, use production to predict tomorrow's quantity
            double x = Math.max(observer.getLastUntrasformedQuantityTraded(), dept.getTodayInflow()) + increaseStep;
            if (observer.getQuantityTransformer() != null)
                x = observer.getQuantityTransformer().transform(x);
            double y = regression.predict(x);
            if (observer.getPriceTransformer() != null) {
                assert observer.getPriceInverseTransformer() != null;
                y = observer.getPriceInverseTransformer().transform(y);
            }

            return (int) Math.round(y);
        }

    }

    /**
     * This is called by the firm when it wants to predict the price they can sell to if they increase production
     *
     *
     * @param dept                   the sales department that has to answer this question
     * @param expectedProductionCost the HQ estimate of costs in producing whatever it wants to sell. It isn't necesarilly used.
     * @param decreaseStep ignored
     * @return the best offer available/predicted or -1 if there are no quotes/good predictions
     */
    @Override
    public float predictSalePriceAfterDecreasingProduction(SalesDepartment dept, int expectedProductionCost,
            int decreaseStep) {
        Preconditions.checkArgument(decreaseStep >= 0);
        //regress and return
        updateModel();

        if (Double.isNaN(regression.getIntercept())) //if we couldn't do a regression, just return today's pricing
            return dept.hypotheticalSalePrice();
        else {
            //if you are producing more than what's sold, use production to predict tomorrow's quantity
            double x = Math.max(observer.getLastUntrasformedQuantityTraded(), dept.getTodayInflow()) - decreaseStep;
            if (observer.getQuantityTransformer() != null)
                x = observer.getQuantityTransformer().transform(x);
            double y = regression.predict(x);
            if (observer.getPriceTransformer() != null) {
                assert observer.getPriceInverseTransformer() != null;
                y = observer.getPriceInverseTransformer().transform(y);
            }

            return (int) Math.round(y);
        }

    }

    /**
     * Force the predictor to run a regression, if possible
     */
    public void updateModel() {
        if (observer.getNumberOfObservations() > 2)
            regression.estimateModel(observer.getQuantitiesConsumedObservedAsArray(),
                    observer.getPricesObservedAsArray(), null);
    }

    /**
     * Call this to kill the predictor
     */
    @Override
    public void turnOff() {

        super.turnOff();
        observer.turnOff();
    }

    /**
     * Gets the intercept of the estimated model.
     *
     * @return Value of the intercept of the estimated model.
     */
    public double getIntercept() {
        return regression.getIntercept();
    }

    /**
     * Gets the slope of the estimated model.
     *
     * @return Value of the slope of the estimated model.
     */
    public double getSlope() {
        return regression.getSlope();
    }

    protected LinearRegression getRegression() {
        return regression;
    }

    public Transformer<Double, Double> getPriceInverseTransformer() {
        return observer.getPriceInverseTransformer();
    }

    /**
     * Gets A function we can put in to transform the observed price before reading it in.
     *
     * @return Value of A function we can put in to transform the observed price before reading it in.
     */
    public Transformer<Double, Double> getPriceTransformer() {
        return observer.getPriceTransformer();
    }

    /**
     * Sets new A function we can put in to transform the observed price before reading it in.
     *
     * @param priceTransformer New value of A function we can put in to transform the observed price before reading it in.
     */
    public void setPriceTransformer(Transformer<Double, Double> priceTransformer,
            Transformer<Double, Double> priceInverseTransformer) {
        observer.setPriceTransformer(priceTransformer, priceInverseTransformer);
    }

    /**
     * Gets A function we can put in to transform the observed price before reading it in.
     *
     * @return Value of A function we can put in to transform the observed price before reading it in.
     */
    public Transformer<Double, Double> getQuantityTransformer() {
        return observer.getQuantityTransformer();
    }

    /**
     * Sets new A function we can put in to transform the observed price before reading it in.
     *
     * @param quantityTransformer New value of A function we can put in to transform the observed price before reading it in.
     */
    public void setQuantityTransformer(Transformer<Double, Double> quantityTransformer) {
        observer.setQuantityTransformer(quantityTransformer);
    }

    public int numberOfObservations() {
        return observer.getNumberOfObservations();
    }

    /**
     * get the last (newest) observation day
     * @return
     */
    public Double getLastDayObserved() {
        return observer.getLastDayObserved();
    }

    /**
     * get the last (newest) observation of price
     * @return
     */
    public Double getLastPriceObserved() {
        return observer.getLastPriceObserved();
    }

    /**
     * get the last (newest) observation of quantity
     * @return
     */
    public Double getLastQuantityObserved() {
        return observer.getLastQuantityTradedObserved();
    }

    public void setDailyProbabilityOfObserving(float dailyProbabilityOfObserving) {
        observer.setDailyProbabilityOfObserving(dailyProbabilityOfObserving);
    }

    public float getDailyProbabilityOfObserving() {
        return observer.getDailyProbabilityOfObserving();
    }

    /**
     * get the last (newest) observation of quantity
     * @return
     */
    public Double getLastQuantityProducedObserved() {
        return observer.getLastQuantityProducedObserved();
    }

    /**
     * get the last (newest) observation of quantity
     * @return
     */
    public Double getLastQuantityTradedObserved() {
        return observer.getLastQuantityTradedObserved();
    }

    /**
     * get the last (newest) observation of quantity
     * @return
     */
    public Double getLastQuantityConsumedObserved() {
        return observer.getLastQuantityConsumedObserved();
    }

    public double getLastUntrasformedQuantityTraded() {
        return observer.getLastUntrasformedQuantityTraded();
    }

    public double getLastUntrasformedPrice() {
        return observer.getLastUntrasformedPrice();
    }

    @Override
    public String toString() {
        return regression.toString();
    }

    /**
     * This is a little bit weird to predict, but basically you want to know what will be "tomorrow" price if you don't change production.
     * Most predictors simply return today closing price, because maybe this will be useful in some cases. It's used by Marginal Maximizer Statics
     *
     * @param dept the sales department
     * @return predicted price
     */
    @Override
    public float predictSalePriceWhenNotChangingProduction(SalesDepartment dept) {
        //regress and return
        updateModel();

        if (Double.isNaN(regression.getIntercept())) //if we couldn't do a regression, just return today's pricing
            return dept.hypotheticalSalePrice();
        else {
            //if you are producing more than what's sold, use production to predict tomorrow's quantity
            double x = Math.max(observer.getLastUntrasformedQuantityTraded(), dept.getTodayInflow());
            if (observer.getQuantityTransformer() != null)
                x = observer.getQuantityTransformer().transform(x);
            double y = regression.predict(x);
            if (observer.getPriceTransformer() != null) {
                assert observer.getPriceInverseTransformer() != null;
                y = observer.getPriceInverseTransformer().transform(y);
            }

            return (int) Math.round(y);
        }

    }
}