Selection of Stocks into a Portfilio
In the current document we show how you can pick the best stock and strategy combinations out of a big collecion from a universe.
Setup
Import Libraries
%classpath config resolver maven-public http://software.pschatzmann.ch/repository/maven-public/
%classpath add mvn ch.pschatzmann:investor:0.9-SNAPSHOT
%classpath add mvn ch.pschatzmann:jupyter-jdk-extensions:0.0.1-SNAPSHOT
Imports
// our stock evaluation framwork
import ch.pschatzmann.dates._;
import ch.pschatzmann.stocks._;
import ch.pschatzmann.stocks.data.universe._;
import ch.pschatzmann.stocks.input._;
import ch.pschatzmann.stocks.accounting._;
import ch.pschatzmann.stocks.accounting.kpi._;
import ch.pschatzmann.stocks.execution._;
import ch.pschatzmann.stocks.execution.fees._;
import ch.pschatzmann.stocks.execution.price._;
import ch.pschatzmann.stocks.parameters._;
import ch.pschatzmann.stocks.strategy._;
import ch.pschatzmann.stocks.strategy.optimization._;
import ch.pschatzmann.stocks.strategy.allocation._;
import ch.pschatzmann.stocks.strategy.selection._;
import ch.pschatzmann.stocks.integration._;
import ch.pschatzmann.stocks.integration.ChartData.FieldName._;
import ch.pschatzmann.stocks.strategy.OptimizedStrategy.Schedule._;
// java
import java.util.stream.Collectors;
import java.util._;
//import java.util.function.Consumer;
// log4j
import org.apache.log4j._;
/// jupyter custom displayer
import ch.pschatzmann.display.Displayers
import ch.pschatzmann.dates._
import ch.pschatzmann.stocks._
import ch.pschatzmann.stocks.data.universe._
import ch.pschatzmann.stocks.input._
import ch.pschatzmann.stocks.accounting._
import ch.pschatzmann.stocks.accounting.kpi._
import ch.pschatzmann.stocks.execution._
import ch.pschatzmann.stocks.execution.fees._
import ch.pschatzmann.stocks.execution.price._
import ch.pschatzmann.stocks.parameters._
import ch.pschatzmann.stocks.strategy._
import ch.pschatzmann.stocks.strategy.optimization._
import ch.pschatzmann.stocks.strategy.allocation._
import ch.pschatzmann.stocks.strategy.selection._
import ch.pschatzmann.stocks.integration._
import ch.pschatzmann.stocks.integration.ChartData.FieldName._
import ch.pschatzmann.stocks.strategy.OptimizedStrategy.Schedule._
import java.util.stream...
Deactivate Logging and Caching
var root = Logger.getRootLogger();
root.setLevel(Level.ERROR);
Context.setCachingActive(false);
Context.isCachingActive();
false
Selection of all Stocks and Strategies
First we need to specify the strategies that we want to use for the evaluation. We just use all:
TradingStrategyFactory.list()
[CCICorrectionStrategy, GlobalExtremaStrategy, MovingMomentumStrategy, RSI2Strategy, BuyAndHoldStrategy]
For defining the selection of stocks we use a universe
new MarketUniverse("NASDAQ")
MarketUniverese: exchange=NASDAQ ticker=.*
and we define the optimization period as 2016-01-01-2016-21-31 and the trading period as
2017-01-01 to today:
Context.getDateRanges("2016-01-01","2017-01-01");
[20160101-20161231, 20170101-20180527]
Run the Selection – 1st Attempt
We define a StrategySelector and feed it to the StockSelector.
The optional Restartable parameter is making sure that we save the temporary result every 50 records so that we do not need to reprocess them when we need to restart the functionality.
We store the result in a file and make sure that we do not run the selection again if the file already exists.
// setup of the model
var periods = Context.getDateRanges("2016-01-01","2017-01-01");
var account = new Account("Simulation", "USD", 100000.00, periods.get(0).getStart(), new PerTradeFees(100.00))
var file = new java.io.File("NASDAQ-2017-01-01.json")
if (!file.exists()) {
var universe = new MarketUniverse("NASDAQ")
var strategies = TradingStrategyFactory.list()
var strategySelector = new StrategySelector(account, strategies, periods.get(0), KPI.AbsoluteReturn)
var stockSelector = new StockSelector(strategySelector, new Restartable("restart-v1.ser",50))
// calculate the result
var result = stockSelector.getSelection(200, universe, new MarketArchiveHttpReader())
// save the result to a file
result.save(file)
}
// provide result even if we did not run the selection above
var result = new SelectionResult()
result.load(file)
"**END**"
**END**
Evaluate the Selection
Here is the result of the selection:
Displayers.display(Context.tail(result.getResult(),10));
input |
result |
stockID |
strategyName |
optimized |
Key |
Value |
parameters |
{NumberOfTicks={value=7.0, range={min=1, max=500}}, BuyFactor={value=1.0, range={min=1.001, max=5.0}}, SellFactor={value=1.0, range={min=0.005, max=0.999}}} |
|
Key |
Value |
parameters |
{RealizedGains={value=28314.0, range=null}, Cash={value=10.0, range=null}, ReturnPercent={value=20.0, range=null}, NumberOfBuys={value=7.0, range=null}, ReturnPercentAnualized={value=10.0, range=null}, MaxDrawDownHighValue={value=148193.0, range=null}, NumberOfCashTransfers={value=1.0, range=null}, AbsoluteReturnStdDev={value=2483.0, range=null}, MaxDrawDownNumberOfDays={value=185.0, range=null}, AbsoluteReturnAvaragePerDay={value=39.0, range=null}, NumberOfSells={value=6.0, range=null}, ActualValue={value=120332.0, range=null}, UnrealizedGains={value=-6683.0, range=null}, PurchasedValue={value=127014.0, range=null}, MaxDrawDownPercent={value=68951.0, range=null}, NumberOfTradedStocks={value=1.0, range=null}, MaxDrawDownLowValue={value=79242.0, range=null}, AbsoluteReturn={value=20332.0, range=null}, ReturnPurcentStdDev={value=0.0, range=null}, SharpeRatio={value=0.0, range=null}, NumberOfTrades={value=13.0, range=null}, TotalFees={value=1300.0, range=null}} |
|
Key |
Value |
ticker |
MYRG |
exchange |
NASDAQ |
|
GlobalExtremaStrategy |
false |
Key |
Value |
parameters |
{SignalEMA={value=18.0, range={min=16, max=20}}, EntrySignal={value=20.0, range={min=10, max=30}}, ExitSignal={value=80.0, range={min=70, max=90}}, ShortEMAPeriod={value=9.0, range={min=1, max=20}}, StochasticOscillatorKIndicator={value=14.0, range={min=7, max=21}}, LongEMAPeriod={value=26.0, range={min=20, max=40}}} |
|
Key |
Value |
parameters |
{RealizedGains={value=20387.0, range=null}, Cash={value=120187.0, range=null}, ReturnPercent={value=20.0, range=null}, NumberOfBuys={value=1.0, range=null}, ReturnPercentAnualized={value=10.0, range=null}, MaxDrawDownHighValue={value=103986.0, range=null}, NumberOfCashTransfers={value=1.0, range=null}, AbsoluteReturnStdDev={value=1070.0, range=null}, MaxDrawDownNumberOfDays={value=56.0, range=null}, AbsoluteReturnAvaragePerDay={value=41.0, range=null}, NumberOfSells={value=1.0, range=null}, ActualValue={value=120187.0, range=null}, UnrealizedGains={value=0.0, range=null}, PurchasedValue={value=120187.0, range=null}, MaxDrawDownPercent={value=14888.0, range=null}, NumberOfTradedStocks={value=1.0, range=null}, MaxDrawDownLowValue={value=89098.0, range=null}, AbsoluteReturn={value=20187.0, range=null}, ReturnPurcentStdDev={value=0.0, range=null}, SharpeRatio={value=1.0, range=null}, NumberOfTrades={value=2.0, range=null}, TotalFees={value=200.0, range=null}} |
|
Key |
Value |
ticker |
TMUSP |
exchange |
NASDAQ |
|
MovingMomentumStrategy |
false |
Key |
Value |
parameters |
{SignalEMA={value=18.0, range={min=16, max=20}}, EntrySignal={value=20.0, range={min=10, max=30}}, ExitSignal={value=80.0, range={min=70, max=90}}, ShortEMAPeriod={value=9.0, range={min=1, max=20}}, StochasticOscillatorKIndicator={value=14.0, range={min=7, max=21}}, LongEMAPeriod={value=26.0, range={min=20, max=40}}} |
|
Key |
Value |
parameters |
{RealizedGains={value=20333.0, range=null}, Cash={value=120133.0, range=null}, ReturnPercent={value=20.0, range=null}, NumberOfBuys={value=1.0, range=null}, ReturnPercentAnualized={value=10.0, range=null}, MaxDrawDownHighValue={value=118822.0, range=null}, NumberOfCashTransfers={value=1.0, range=null}, AbsoluteReturnStdDev={value=947.0, range=null}, MaxDrawDownNumberOfDays={value=48.0, range=null}, AbsoluteReturnAvaragePerDay={value=39.0, range=null}, NumberOfSells={value=1.0, range=null}, ActualValue={value=120133.0, range=null}, UnrealizedGains={value=0.0, range=null}, PurchasedValue={value=120133.0, range=null}, MaxDrawDownPercent={value=11666.0, range=null}, NumberOfTradedStocks={value=1.0, range=null}, MaxDrawDownLowValue={value=107156.0, range=null}, AbsoluteReturn={value=20133.0, range=null}, ReturnPurcentStdDev={value=0.0, range=null}, SharpeRatio={value=1.0, range=null}, NumberOfTrades={value=2.0, range=null}, TotalFees={value=200.0, range=null}} |
|
Key |
Value |
ticker |
NICE |
exchange |
NASDAQ |
|
MovingMomentumStrategy |
false |
Key |
Value |
parameters |
{NumberOfTicks={value=7.0, range={min=1, max=500}}, BuyFactor={value=1.0, range={min=1.001, max=5.0}}, SellFactor={value=1.0, range={min=0.005, max=0.999}}} |
|
Key |
Value |
parameters |
{RealizedGains={value=20730.0, range=null}, Cash={value=120130.0, range=null}, ReturnPercent={value=20.0, range=null}, NumberOfBuys={value=3.0, range=null}, ReturnPercentAnualized={value=10.0, range=null}, MaxDrawDownHighValue={value=115644.0, range=null}, NumberOfCashTransfers={value=1.0, range=null}, AbsoluteReturnStdDev={value=1114.0, range=null}, MaxDrawDownNumberOfDays={value=88.0, range=null}, AbsoluteReturnAvaragePerDay={value=39.0, range=null}, NumberOfSells={value=3.0, range=null}, ActualValue={value=120130.0, range=null}, UnrealizedGains={value=0.0, range=null}, PurchasedValue={value=120130.0, range=null}, MaxDrawDownPercent={value=15780.0, range=null}, NumberOfTradedStocks={value=1.0, range=null}, MaxDrawDownLowValue={value=99863.0, range=null}, AbsoluteReturn={value=20130.0, range=null}, ReturnPurcentStdDev={value=0.0, range=null}, SharpeRatio={value=1.0, range=null}, NumberOfTrades={value=6.0, range=null}, TotalFees={value=600.0, range=null}} |
|
Key |
Value |
ticker |
MGPI |
exchange |
NASDAQ |
|
GlobalExtremaStrategy |
false |
Key |
Value |
parameters |
{EntryLimit={value=5.0, range={min=2, max=10}}, RSIPeriod={value=2.0, range={min=1, max=5}}, LongSMAPeriod={value=200.0, range={min=100, max=300}}, ShortSMAPeriod={value=5.0, range={min=2, max=10}}, ExitLimit={value=95.0, range={min=85, max=98}}} |
|
Key |
Value |
parameters |
{RealizedGains={value=-3467.0, range=null}, Cash={value=4.0, range=null}, ReturnPercent={value=20.0, range=null}, NumberOfBuys={value=2.0, range=null}, ReturnPercentAnualized={value=10.0, range=null}, MaxDrawDownHighValue={value=110489.0, range=null}, NumberOfCashTransfers={value=1.0, range=null}, AbsoluteReturnStdDev={value=1242.0, range=null}, MaxDrawDownNumberOfDays={value=370.0, range=null}, AbsoluteReturnAvaragePerDay={value=39.0, range=null}, NumberOfSells={value=1.0, range=null}, ActualValue={value=120122.0, range=null}, UnrealizedGains={value=23889.0, range=null}, PurchasedValue={value=96233.0, range=null}, MaxDrawDownPercent={value=23597.0, range=null}, NumberOfTradedStocks={value=1.0, range=null}, MaxDrawDownLowValue={value=86892.0, range=null}, AbsoluteReturn={value=20122.0, range=null}, ReturnPurcentStdDev={value=0.0, range=null}, SharpeRatio={value=1.0, range=null}, NumberOfTrades={value=3.0, range=null}, TotalFees={value=300.0, range=null}} |
|
Key |
Value |
ticker |
DENN |
exchange |
NASDAQ |
|
RSI2Strategy |
false |
Key |
Value |
parameters |
{ShortCCIPeriod={value=5.0, range={min=1, max=100}}, Signal={value=100.0, range={min=90, max=110}}, LongCCIPeriod={value=200.0, range={min=100, max=300}}} |
|
Key |
Value |
parameters |
{RealizedGains={value=0.0, range=null}, Cash={value=1.0, range=null}, ReturnPercent={value=20.0, range=null}, NumberOfBuys={value=1.0, range=null}, ReturnPercentAnualized={value=10.0, range=null}, MaxDrawDownHighValue={value=107979.0, range=null}, NumberOfCashTransfers={value=1.0, range=null}, AbsoluteReturnStdDev={value=2220.0, range=null}, MaxDrawDownNumberOfDays={value=160.0, range=null}, AbsoluteReturnAvaragePerDay={value=39.0, range=null}, NumberOfSells={value=0.0, range=null}, ActualValue={value=119998.0, range=null}, UnrealizedGains={value=20098.0, range=null}, PurchasedValue={value=99900.0, range=null}, MaxDrawDownPercent={value=28571.0, range=null}, NumberOfTradedStocks={value=1.0, range=null}, MaxDrawDownLowValue={value=79408.0, range=null}, AbsoluteReturn={value=19998.0, range=null}, ReturnPurcentStdDev={value=0.0, range=null}, SharpeRatio={value=0.0, range=null}, NumberOfTrades={value=1.0, range=null}, TotalFees={value=100.0, range=null}} |
|
Key |
Value |
ticker |
PTNR |
exchange |
NASDAQ |
|
CCICorrectionStrategy |
false |
Key |
Value |
parameters |
{NumberOfTicks={value=7.0, range={min=1, max=500}}, BuyFactor={value=1.0, range={min=1.001, max=5.0}}, SellFactor={value=1.0, range={min=0.005, max=0.999}}} |
|
Key |
Value |
parameters |
{RealizedGains={value=23187.0, range=null}, Cash={value=119987.0, range=null}, ReturnPercent={value=20.0, range=null}, NumberOfBuys={value=16.0, range=null}, ReturnPercentAnualized={value=10.0, range=null}, MaxDrawDownHighValue={value=101788.0, range=null}, NumberOfCashTransfers={value=1.0, range=null}, AbsoluteReturnStdDev={value=584.0, range=null}, MaxDrawDownNumberOfDays={value=44.0, range=null}, AbsoluteReturnAvaragePerDay={value=39.0, range=null}, NumberOfSells={value=16.0, range=null}, ActualValue={value=119987.0, range=null}, UnrealizedGains={value=0.0, range=null}, PurchasedValue={value=119987.0, range=null}, MaxDrawDownPercent={value=7803.0, range=null}, NumberOfTradedStocks={value=1.0, range=null}, MaxDrawDownLowValue={value=93985.0, range=null}, AbsoluteReturn={value=19987.0, range=null}, ReturnPurcentStdDev={value=0.0, range=null}, SharpeRatio={value=1.0, range=null}, NumberOfTrades={value=32.0, range=null}, TotalFees={value=3200.0, range=null}} |
|
Key |
Value |
ticker |
BICK |
exchange |
NASDAQ |
|
GlobalExtremaStrategy |
false |
Key |
Value |
parameters |
{NumberOfTicks={value=7.0, range={min=1, max=500}}, BuyFactor={value=1.0, range={min=1.001, max=5.0}}, SellFactor={value=1.0, range={min=0.005, max=0.999}}} |
|
Key |
Value |
parameters |
{RealizedGains={value=22182.0, range=null}, Cash={value=119782.0, range=null}, ReturnPercent={value=20.0, range=null}, NumberOfBuys={value=12.0, range=null}, ReturnPercentAnualized={value=10.0, range=null}, MaxDrawDownHighValue={value=102274.0, range=null}, NumberOfCashTransfers={value=1.0, range=null}, AbsoluteReturnStdDev={value=623.0, range=null}, MaxDrawDownNumberOfDays={value=73.0, range=null}, AbsoluteReturnAvaragePerDay={value=38.0, range=null}, NumberOfSells={value=12.0, range=null}, ActualValue={value=119782.0, range=null}, UnrealizedGains={value=0.0, range=null}, PurchasedValue={value=119782.0, range=null}, MaxDrawDownPercent={value=11169.0, range=null}, NumberOfTradedStocks={value=1.0, range=null}, MaxDrawDownLowValue={value=91104.0, range=null}, AbsoluteReturn={value=19782.0, range=null}, ReturnPurcentStdDev={value=0.0, range=null}, SharpeRatio={value=1.0, range=null}, NumberOfTrades={value=24.0, range=null}, TotalFees={value=2400.0, range=null}} |
|
Key |
Value |
ticker |
UCBA |
exchange |
NASDAQ |
|
GlobalExtremaStrategy |
false |
Key |
Value |
parameters |
{NumberOfTicks={value=7.0, range={min=1, max=500}}, BuyFactor={value=1.0, range={min=1.001, max=5.0}}, SellFactor={value=1.0, range={min=0.005, max=0.999}}} |
|
Key |
Value |
parameters |
{RealizedGains={value=20514.0, range=null}, Cash={value=119714.0, range=null}, ReturnPercent={value=20.0, range=null}, NumberOfBuys={value=4.0, range=null}, ReturnPercentAnualized={value=10.0, range=null}, MaxDrawDownHighValue={value=121480.0, range=null}, NumberOfCashTransfers={value=1.0, range=null}, AbsoluteReturnStdDev={value=1171.0, range=null}, MaxDrawDownNumberOfDays={value=496.0, range=null}, AbsoluteReturnAvaragePerDay={value=38.0, range=null}, NumberOfSells={value=4.0, range=null}, ActualValue={value=119714.0, range=null}, UnrealizedGains={value=0.0, range=null}, PurchasedValue={value=119714.0, range=null}, MaxDrawDownPercent={value=22261.0, range=null}, NumberOfTradedStocks={value=1.0, range=null}, MaxDrawDownLowValue={value=99219.0, range=null}, AbsoluteReturn={value=19714.0, range=null}, ReturnPurcentStdDev={value=0.0, range=null}, SharpeRatio={value=1.0, range=null}, NumberOfTrades={value=8.0, range=null}, TotalFees={value=800.0, range=null}} |
|
Key |
Value |
ticker |
DSPG |
exchange |
NASDAQ |
|
GlobalExtremaStrategy |
false |
Key |
Value |
parameters |
{ShortCCIPeriod={value=5.0, range={min=1, max=100}}, Signal={value=100.0, range={min=90, max=110}}, LongCCIPeriod={value=200.0, range={min=100, max=300}}} |
|
Key |
Value |
parameters |
{RealizedGains={value=0.0, range=null}, Cash={value=2.0, range=null}, ReturnPercent={value=20.0, range=null}, NumberOfBuys={value=1.0, range=null}, ReturnPercentAnualized={value=10.0, range=null}, MaxDrawDownHighValue={value=154090.0, range=null}, NumberOfCashTransfers={value=1.0, range=null}, AbsoluteReturnStdDev={value=2344.0, range=null}, MaxDrawDownNumberOfDays={value=259.0, range=null}, AbsoluteReturnAvaragePerDay={value=38.0, range=null}, NumberOfSells={value=0.0, range=null}, ActualValue={value=119681.0, range=null}, UnrealizedGains={value=19781.0, range=null}, PurchasedValue={value=99900.0, range=null}, MaxDrawDownPercent={value=38559.0, range=null}, NumberOfTradedStocks={value=1.0, range=null}, MaxDrawDownLowValue={value=115531.0, range=null}, AbsoluteReturn={value=19681.0, range=null}, ReturnPurcentStdDev={value=0.0, range=null}, SharpeRatio={value=0.0, range=null}, NumberOfTrades={value=1.0, range=null}, TotalFees={value=100.0, range=null}} |
|
Key |
Value |
ticker |
PFBX |
exchange |
NASDAQ |
|
CCICorrectionStrategy |
false |
Finally we use the selected result as our portfolio and we can run a simulation on it for the
last year:
var account = new Account("Simulation","USD", 100000.00, periods.get(0).getStart(), new PerTradeFees(10.0));
var trader = new PaperTrader(account);
var allocationStrategy = new DistributedAllocationStrategy(trader);
var executor = new StrategyExecutor(trader, allocationStrategy);
executor.addStrategy(result.getStrategies(new MarketArchiveHttpReader()));
executor.run(periods.get(1));
println(account.getKPIValues())
[Absolute Return 25033.923488616943, Absolute Return Avarage per day 48.51535559809485, Absolute Return StdDev 779.2345876615038, Return % 25.033923488616942, Return % per year 12.202221893871315, Return % StdDev 0.007057396060496201, Sharp Ratio 1.0300644489363013, Max Draw Down % 7.728977897596769, Max Draw Down Absolute 9628.355476379395, Max Draw Down - Number of days 45, Max Draw Down - High 124574.7575416565, Max Draw Down - Low 114946.4020652771, Max Draw Down - Period 20171106-20171207, Number of Trades 2, Number of Buys 2, Number of Sells 0, Number of Cash Transfers 1, Number of Traded Stocks 2, Total Fees 20.0, Cash 35.85043716430664, Total Value (at actual rates) including cash 125033.92348861694, Total Value (at purchased rates) 99980.0, Realized Gains 0.0, Unrealized Gains 25053.923488616943]
null
Displayers.display(account.getTransactions().collect(Collectors.toList()));
active |
stockID |
date |
quantity |
requestedPrice |
filledPrice |
fees |
comment |
id |
requestedPriceType |
buyOrSell |
impactOnCash |
true |
Key |
Value |
ticker |
Cash |
exchange |
Account |
|
2016-01-01 |
0 |
0 |
0 |
0 |
|
7109bb39-1f69-45ae-8f28-906b80e8486b |
CashTransfer |
NA |
100000 |
true |
Key |
Value |
ticker |
CARZ |
exchange |
NASDAQ |
|
2017-01-04 |
1426 |
0 |
35.0391 |
10 |
|
dc256381-c8cb-47f7-8c3c-98239b9672a5 |
Market |
Buy |
-49975.7303 |
true |
Key |
Value |
ticker |
PAHC |
exchange |
NASDAQ |
|
2017-01-04 |
1718 |
0 |
29.091 |
10 |
|
16b12b8a-09f2-4316-9bb8-af34cbf83b70 |
Market |
Buy |
-49988.4192 |
var chart = new TimeSeriesChart()
chart.add(account.getTotalValueHistory(),"")
Displayers.display(chart.displayChart())
import scala.collection.JavaConversions._
var chart1 = new TimeSeriesChart()
chart1.add(account.getCashHistoryForAllDates(), "Cash");
chart1.add(account.getTotalValueHistory(), "Total Value");
chart1.add(account.getActualValueHistory(), "ActualValue");
for (id <- account.getStockIDs()) {
var data = account.getActualValueHistory(id);
chart1.add(data,id.toString())
}
//chart1.addLabels(account.getTransactions())
Displayers.display(chart1.displayCharts())
Though at first sight it seems to be promising, the result is in fact quite disapointing: We only get 2 stocks which are used for trading and they are just bought and never sold. So it is just by luck that we were successfull!
Run the Selection – 2nd Attempt
On our 2nd trial we want to use the followig additional criteria:
– no penny stocks: rate > 5.0
– activly traded: number of trades >= 4
Therefore we define the following predicates which drive our selection
import ch.pschatzmann.stocks.strategy.selection.SelectionState;
import java.util.function.Predicate;
class NumberOfTradesPredicate( numberOfTrades: Double) extends Predicate[SelectionState] {
override def test(state:SelectionState):scala.Boolean = {
return state.result().getDouble(KPI.NumberOfTrades) > numberOfTrades;
};
}
class PriceLimitPredicate(account:Account, date:Date, limit: Double) extends Predicate[SelectionState] {
override def test(state:SelectionState):scala.Boolean = {
return account.getStockPrice(state.getStockID(), date)>limit;
};
}
import ch.pschatzmann.stocks.strategy.selection.SelectionState
import java.util.function.Predicate
defined class NumberOfTradesPredicate
defined class PriceLimitPredicate
// setup of the model
var periods = Context.getDateRanges("2016-01-01","2017-01-01");
var account = new Account("Simulation", "USD", 100000.00, periods.get(0).getStart(), new PerTradeFees(100.00))
var file = new java.io.File("NASDAQ-2017-01-01A.json")
if (!file.exists()) {
var universe = new MarketUniverse("NASDAQ")
var strategies = TradingStrategyFactory.list()
var predicate = new NumberOfTradesPredicate(4.0).and(new PriceLimitPredicate(account, periods.get(0).getStart(), 5.0));
var strategySelector = new StrategySelector(account, strategies, periods.get(0), KPI.AbsoluteReturn, predicate)
var stockSelector = new StockSelector(strategySelector, new Restartable("restart-v1A.ser",50))
// calculate the result
var result = stockSelector.getSelection(200, universe, new MarketArchiveHttpReader())
// save the result to a file
result.save(file)
}
// provide result even if we did not run the selection above
var resultA = new SelectionResult()
resultA.load(file)
var trader = new PaperTrader(account);
var allocationStrategy = new DistributedAllocationStrategy(trader);
var executor = new StrategyExecutor(trader, allocationStrategy);
executor.addStrategy(resultA.getStrategies(new MarketArchiveHttpReader()));
executor.run(periods.get(1));
account.getKPIValues()
[Absolute Return 0.0, Absolute Return Avarage per day NaN, Absolute Return StdDev NaN, Return % 0.0, Return % per year 0.0, Return % StdDev NaN, Sharp Ratio NaN, Max Draw Down % null, Max Draw Down Absolute null, Max Draw Down - Number of days null, Max Draw Down - High null, Max Draw Down - Low null, Max Draw Down - Period null, Number of Trades 0, Number of Buys 0, Number of Sells 0, Number of Cash Transfers 1, Number of Traded Stocks 0, Total Fees 0.0, Cash 100000.0, Total Value (at actual rates) including cash 100000.0, Total Value (at purchased rates) 100000.0, Realized Gains 0.0, Unrealized Gains 0.0]
Selection with Sharpe Ratio
In the long run we might be better off by using the Sharpe Ratio instead of the Absolute Return as selection criterium. So here is our next try:
// setup of the model
var periods = Context.getDateRanges("2016-01-01","2017-01-01");
var account = new Account("Simulation", "USD", 100000.00, periods.get(0).getStart(), new PerTradeFees(100.00))
var file = new java.io.File("NASDAQ-2017-01-01S.json")
if (!file.exists()) {
var universe = new MarketUniverse("NASDAQ")
var strategies = TradingStrategyFactory.list()
var strategySelector = new StrategySelector(account, strategies, periods.get(0), KPI.SharpeRatio)
var stockSelector = new StockSelector(strategySelector, new Restartable("restart-v1S.ser",50))
// calculate the result
var result = stockSelector.getSelection(200, universe, new MarketArchiveHttpReader())
// save the result to a file
result.save(file)
}
// provide result even if we did not run the selection above
var resultS = new SelectionResult()
resultS.load(file)
var trader = new PaperTrader(account);
var allocationStrategy = new DistributedAllocationStrategy(trader);
var executor = new StrategyExecutor(trader, allocationStrategy);
executor.addStrategy(resultS.getStrategies(new MarketArchiveHttpReader()));
executor.run(periods.get(1));
account.getKPIValues()
[Absolute Return -95743.38202537596, Absolute Return Avarage per day -187.73212161838424, Absolute Return StdDev 5843.812344481103, Return % -95.74338202537596, Return % per year -47.21591442347308, Return % StdDev 0.07739180282189885, Sharp Ratio -0.6909314558908972, Max Draw Down % 98.06741328837373, Max Draw Down Absolute 211245.8531461507, Max Draw Down - Number of days 251, Max Draw Down - High 215408.8152860403, Max Draw Down - Low 4162.962139889598, Max Draw Down - Period 20170111-20180104, Number of Trades 1, Number of Buys 1, Number of Sells 0, Number of Cash Transfers 1, Number of Traded Stocks 1, Total Fees 100.0, Cash 0.482232928276062, Total Value (at actual rates) including cash 4256.617974624038, Total Value (at purchased rates) 99900.0, Realized Gains 0.0, Unrealized Gains -95643.38202537596]
Electronic Monkey
We can compare the results above with an Monkey Picker which just pick 50 random stocks and strategies
var account = new Account("Simulation","USD", 1000000.00, periods.get(0).getStart(), new PerTradeFees(10.0));
var trader = new PaperTrader(account);
var allocationStrategy = new DistributedAllocationStrategy(trader);
var executor = new StrategyExecutor(trader, allocationStrategy);
var randomStrategies = TradingStrategyFactory.getRandomStrategies(new MarketUniverse("NASDAQ"),new MarketArchiveHttpReader(), 50)
executor.addStrategy(randomStrategies);
executor.run(periods.get(1));
println(account.getKPIValues())
Optimization
We can also evaluate if parameter optimization makes a difference. We optimize the parameters based
on the closing rates of the year 2015. Then we select the stocks that perfomred best in 2016.
Finally we evaluate the performance for 2017
// setup of the model in background
var periods = Context.getDateRanges("2015-01-01","2016-01-01","2017-01-01","2018-01-01")
var account = new Account("Simulation", "USD", 100000.00, periods.get(0).getStart(), new PerTradeFees(100.00))
var file = new java.io.File("NASDAQ-2017-01-01-optimized.json")
if (!file.exists()) {
// run selection
var universe = new MarketUniverse("NASDAQ")
var strategies = TradingStrategyFactory.list()
var optimizer = new BinarySearchOptimizer(new SimulatedFitness(account), KPI.AbsoluteReturn)
var strategySelector = new StrategySelectorOptimized(account, strategies, periods.get(0), periods.get(1), optimizer)
var stockSelector = new StockSelector(strategySelector, new Restartable("restart-v2.ser",20))
// calculate the result
var resultOptimized = stockSelector.getSelection(200, universe, new MarketArchiveHttpReader())
// save the result to a file
resultOptimized.save(file)
}
// Run evaluation
var resultOptimized = new SelectionResult()
resultOptimized.load(file)
var trader = new PaperTrader(account);
var allocationStrategy = new DistributedAllocationStrategy(trader);
var executor = new StrategyExecutor(trader, allocationStrategy);
executor.addStrategy(resultOptimized.getStrategies(new MarketArchiveHttpReader()));
executor.run(periods.get(2));
account.getKPIValues()
Displayers.display(account.getTransactions());
2 Comments
SannyOnerb · 10. December 2018 at 16:07
Make a more new posts please 🙂
___
Sanny
Johnny Zoulek · 28. August 2018 at 7:52
some genuinely great blog posts on this site, regards for contribution.