• Investor – A Java Quantitative Trading Library


    Investor – A Java Quantitative Trading Library

    Published by pschatzmann on 30. May 2018

    Introduction

    Last year I was busy to build my own project which provides an easy to use functionality to implement and evaluate automatic stock trading strategies. It is implemented in java and therefore can be used in any environment which builds on the JVM.

    It provides the following functionality:
    – Simple access to stock data
    – Declarative formulation of trading strategies
    – Evaluation of trading strategies
    – Optimization of trading strategies
    – Support of portfolio of multiple stocks / trading strategies

    At the end it should be possible to easily formulate and evaluate stock strategy and to evaluate the impact of changes on assumptions.

    In this document we demonstrates the basic functionality using Scala: We are using JupyterLab with the BeakerX Scala Kernel. The Jupyter source code can be found on github. And finally here is the link to the Javadoc.

    Setup

    We need to add the java libraries:

    1. %classpath config resolver maven-public http://software.pschatzmann.ch/repository/maven-public/
    2. %classpath add mvn ch.pschatzmann:investor:0.9-SNAPSHOT
    3. %classpath add mvn ch.pschatzmann:jupyter-jdk-extensions:0.0.1-SNAPSHOT
    Added new repo: maven-public
    

    Imports

    First we define all the imports which are used in this demo:

    1. // our stock evaluation framwork
    2. import ch.pschatzmann.dates._;
    3. import ch.pschatzmann.stocks._;
    4. import ch.pschatzmann.stocks.data.universe._;
    5. import ch.pschatzmann.stocks.input._;
    6. import ch.pschatzmann.stocks.accounting._;
    7. import ch.pschatzmann.stocks.accounting.kpi._;
    8. import ch.pschatzmann.stocks.execution._;
    9. import ch.pschatzmann.stocks.execution.fees._;
    10. import ch.pschatzmann.stocks.execution.price._;
    11. import ch.pschatzmann.stocks.parameters._;
    12. import ch.pschatzmann.stocks.strategy._;
    13. import ch.pschatzmann.stocks.strategy.optimization._;
    14. import ch.pschatzmann.stocks.strategy.allocation._;
    15. import ch.pschatzmann.stocks.strategy.selection._;
    16. import ch.pschatzmann.stocks.integration._;
    17. import ch.pschatzmann.stocks.integration.ChartData.FieldName._;
    18. import ch.pschatzmann.stocks.strategy.OptimizedStrategy.Schedule._;
    19. // java
    20. import java.util.stream.Collectors;
    21. import java.util._;
    22. import java.lang._;
    23. import java.util.function.Consumer;
    24. // ta4j
    25. import org.ta4j.core._;
    26. import org.ta4j.core.analysis._;
    27. import org.ta4j.core.analysis.criteria._;
    28. import org.ta4j.core.indicators._;
    29. import org.ta4j.core.indicators.helpers._;
    30. import org.ta4j.core.trading.rules._;
    31. // jupyter custom displayer
    32. import ch.pschatzmann.display.Displayers
    1. import ch.pschatzmann.dates._
    2. import ch.pschatzmann.stocks._
    3. import ch.pschatzmann.stocks.data.universe._
    4. import ch.pschatzmann.stocks.input._
    5. import ch.pschatzmann.stocks.accounting._
    6. import ch.pschatzmann.stocks.accounting.kpi._
    7. import ch.pschatzmann.stocks.execution._
    8. import ch.pschatzmann.stocks.execution.fees._
    9. import ch.pschatzmann.stocks.execution.price._
    10. import ch.pschatzmann.stocks.parameters._
    11. import ch.pschatzmann.stocks.strategy._
    12. import ch.pschatzmann.stocks.strategy.optimization._
    13. import ch.pschatzmann.stocks.strategy.allocation._
    14. import ch.pschatzmann.stocks.strategy.selection._
    15. import ch.pschatzmann.stocks.integration._
    16. import ch.pschatzmann.stocks.integration.ChartData.FieldName._
    17. import ch.pschatzmann.stocks.strategy.OptimizedStrategy.Schedule._
    18. import java.util.stream...

    We register the automatic displayers for charts. We are also not interested in information messages from the log, so we define a higher log level:

    1. Displayers.setup("WARN")
    true
    

    Basic Data Structures: Universe, StockID, StockData

    A StockID is identifiying a stock by the trading symbol and the exchange.

    The Uninverse is a collection of StockIDs. We can use the universe to find stocks or to process a collection relevant stocks.
    – QuandlWIKIUniverse
    – QuandlSixUniverse
    – QuandlEuronextUniverse
    – MarketUniverse
    – JsonUniverse
    – ListUniverse

    1. var universe = new ListUniverse(Arrays.asList(new StockID("AAPL","NASDAQ")));
    2. var values = universe.list();
    3. Displayers.display(values)
    tickerexchange
    AAPLNASDAQ
    1. var universe = new QuandlSixUniverse();
    2. var values = Context.head(universe.list(),10);
    3. Displayers.display(values)
    tickerexchange
    ARP290071876CHFSIX
    AN8068571086CHFSIX
    AT0000652011CHFSIX
    AT0000741053CHFSIX
    AT0000606306CHFSIX
    AT0000676903CHFSIX
    AT0000743059CHFSIX
    AT0000644505CHFSIX
    AT0000720008CHFSIX
    AT0000697750CHFSIX

    Just as a side note: The API provides java collections. It is possible to convert them to a Scala type – e.q a Seq.

    1. var universe = new IEXUniverse();
    2. var values = Context.head(universe.list(),10);
    3. Displayers.display(values)
    tickerexchange
    A
    AA
    AABA
    AAC
    AADR
    AAL
    AAMC
    AAME
    AAN
    AAOI
    1. import scala.collection.JavaConverters;
    2. JavaConverters.asScalaBufferConverter(values).asScala.toSeq
    [[:A, :AA, :AABA, :AAC, :AADR, :AAL, :AAMC, :AAME, :AAN, :AAOI]]
    

    The StockData is the class which provides the history of stock rates and some stock related KPIs. We need to indicate a Reader which defines the source of the data.

    Currently we support
    – YahooReader
    – QuandlWIKIReader
    – QuandlSixReader
    – MarketArchiveHttpReader
    – AlphaVantageReader
    – IEXReader

    Here is the example how to retrieve the stock history:

    1. var stockdata = new StockData(new StockID("AAPL", "NASDAQ"), new IEXReader());
    2. Displayers.display(Context.tail(stockdata.getHistory(),10));
    indexdatelowhighopenclosingadjustmentFactorvolume
    12482018-05-14187.86189.01188.1520778772
    12492018-05-15185.1186.78186.4423695159
    12502018-05-16186186.07188.1819183064
    12512018-05-17186.36188186.9917294029
    12522018-05-18186.13187.19186.3118297728
    12532018-05-21186.9106188187.6318400787
    12542018-05-22186.78188.375187.1615240704
    12552018-05-23185.76186.35188.3620058415
    12562018-05-24186.21188.77188.1523233975
    12572018-05-25187.65188.23188.5817460963

    Charts

    Unfortunatly the BeakerX charting currently does not work in Jupyterlab. Therfore we use JFeeChart http://www.jfree.org/jfreechart/.

    Now, we can display a stock chart in just 1 line:

    1. var aapl = new StockData(new StockID("AAPL", "NASDAQ"), new MarketArchiveHttpReader());
    2. new TimeSeriesChart().add(aapl)

    Technical Analysis with TA4J

    Ta4j is an open source Java library for technical analysis. It provides the basic components for creation, evaluation and execution of trading strategies.

    We can use our StockData functionality as data source for TA4J to e.g. to calculate indicators:

    1. var stockData:IStockData = new StockData(new StockID("AAPL", "NASDAQ"), new MarketArchiveHttpReader());
    2. // translate to Ta4j TimeSeries
    3. var series = new Ta4jTimeSeries(stockData, new DateRange(Context.date("2017-01-01"),new Date()));
    4. // Closing Prices
    5. var closePrice:Indicator[Decimal] = new ClosePriceIndicator(series);
    6. // Getting the simple moving average (SMA) of the close price over the last 5 ticks
    7. var shortSma:Indicator[Decimal] = new SMAIndicator(closePrice, 5);
    8. // Getting a longer SMA (e.g. over the 30 last ticks)
    9. var longSma:Indicator[Decimal] = new SMAIndicator(closePrice, 30);
    10. // create chart
    11. var chart = new TimeSeriesChart()
    12. chart.add(shortSma,"shortSma")
    13. chart.add(closePrice,"close")
    14. chart.add(longSma,"longSma")
    15. chart

    Trading with TA4J

    Here is the complete trading and evaluation example which we took from the TA4J documentation that can be found at
    https://github.com/ta4j/ta4j/wiki/Getting%20started.

    The example has been converted to Scala:

    1. var stockData = new StockData(new StockID("AAPL", "NASDAQ"), new MarketArchiveHttpReader());
    2. var series = new Ta4jTimeSeries(stockData);
    3. var closePrice = new ClosePriceIndicator(series);
    4. // Getting the simple moving average (SMA) of the close price over the last 5 ticks
    5. var shortSma = new SMAIndicator(closePrice, 5);
    6. // Getting a longer SMA (e.g. over the 30 last ticks)
    7. var longSma = new SMAIndicator(closePrice, 30);
    8. // Buying rules
    9. // We want to buy:
    10. // - if the 5-ticks SMA crosses over 30-ticks SMA
    11. // - or if the price goes below a defined price (e.g $800.00)
    12. var buyingRule = new CrossedUpIndicatorRule(shortSma, longSma)
    13. .or(new CrossedDownIndicatorRule(closePrice, Decimal.valueOf("800")));
    14. // Selling rules
    15. // We want to sell:
    16. // - if the 5-ticks SMA crosses under 30-ticks SMA
    17. // - or if if the price looses more than 3%
    18. // - or if the price earns more than 2%
    19. var sellingRule = new CrossedDownIndicatorRule(shortSma, longSma)
    20. .or(new StopLossRule(closePrice, Decimal.valueOf("3")))
    21. .or(new StopGainRule(closePrice, Decimal.valueOf("2")));
    22. var strategy = new BaseStrategy(buyingRule, sellingRule);
    23. // Running our juicy trading strategy...
    24. var manager = new TimeSeriesManager(series);
    25. var tradingRecord = manager.run(strategy);
    26. println("Number of trades for our strategy: " + tradingRecord.getTradeCount());
    27. // Getting the cash flow of the resulting trades
    28. var cashFlow = new CashFlow(series, tradingRecord);
    29. // Getting the profitable trades ratio
    30. var profitTradesRatio = new AverageProfitableTradesCriterion();
    31. println("Profitable trades ratio: " + profitTradesRatio.calculate(series, tradingRecord));
    32. // Getting the reward-risk ratio
    33. var rewardRiskRatio = new RewardRiskRatioCriterion();
    34. println("Reward-risk ratio: " + rewardRiskRatio.calculate(series, tradingRecord));
    35. // Total profit of our strategy
    36. // vs total profit of a buy-and-hold strategy
    37. var vsBuyAndHold = new VersusBuyAndHoldCriterion(new TotalProfitCriterion());
    38. println("Our profit vs buy-and-hold profit: " + vsBuyAndHold.calculate(series, tradingRecord));
    39. "--END--"
    1. Number of trades for our strategy: 218
    2. Profitable trades ratio: 0.536697247706422
    3. Reward-risk ratio: 1.8774625448568232
    4. Our profit vs buy-and-hold profit: 0.0019066141135999938
    5. --END--

    So far we have seen how we can use our functionality toghether with TA4J to implement an automatic trading and evaluation platform.

    In the next Chapter we demonstrate our own Trading Simulation and Optimization functionality.

    Accounts and Paper Trader

    The Account class is used to record and evaluate trades. We need to indicate the opening amount, the open date of the account and the Fees Model (IFeesModel).
    We can optionally register a generic reader or a ticker specific reader which defines from where the stock information is read.

    The requested stock trades are recorded with the addTransaction() method. Positive quantities are purchased, negative quantities are sold.

    The paper trader implements the basic trading (simulation) functionality. We can indicate a delay (with setDelay() and the price logic with setPrice(). In our example the trade is executed on the next day with the open rate.

    With the execute() method we start the processing which is processing the open unfilled orders.

    1. var stockdata = new StockID("AAPL", "NASDAQ");
    2. var account = new Account("Simulation","USD", 100000.00, Context.date("2015-01-01"), new PerTradeFees(10.0));
    3. account.putReader(new MarketArchiveHttpReader());
    4. account.addTransaction(new Transaction(Context.date("2015-01-04"), stockdata, +100l));
    5. account.addTransaction(new Transaction(Context.date("2015-10-04"), stockdata, -90l));
    6. var trader = new PaperTrader(account);
    7. // configure alternative logic
    8. trader.setDelay(new OneDayDelay());
    9. trader.setPrice(new OpenPrice());
    10. trader.execute();
    11. // display the resulting transactions
    12. Displayers.display(account.getTransactions());
    activestockIDdatequantityrequestedPricefilledPricefeescommentidimpactOnCashbuyOrSellrequestedPriceType
    true
    KeyValue
    tickerCash
    exchangeAccount
    2015-01-0100007217808a-02f5-4204-8c33-0ffb74e1e423100000NACashTransfer
    true
    KeyValue
    tickerAAPL
    exchangeNASDAQ
    2015-01-051000102.509910d8590f3b-7f8c-4795-8eaa-a01e73ce0f91-10260.9933BuyMarket
    true
    KeyValue
    tickerAAPL
    exchangeNASDAQ
    2015-10-05-900105.336410fd1bd3ec-b5fb-4a86-8521-84e9c20d9d2a9470.2776SellMarket

    Trading Strategies

    The heart of automatic trading are the “trading strategies”. A class which implements ITradingStrategy can be used for automatic trading. A class which implements IOptimizableTradingStrategy can be used for automatic parameter optimization and automatic trading.

    The framework comes with the following standard strategies:

    TradingStrategyFactory.list()
    
    [CCICorrectionStrategy, GlobalExtremaStrategy, MovingMomentumStrategy, RSI2Strategy, BuyAndHoldStrategy]
    

    The Fitness class will be used to evaluate the strategies. As a result it provides both the input and the calculated KPI ouput parameters and updates the account.

    You can use the SimulatedFitness class if you want to avoid the update to the account.

    Displayers.display(account.getTransactions().collect(Collectors.toList()))
    
    activestockIDdatequantityrequestedPricefilledPricefeescommentidimpactOnCashbuyOrSellrequestedPriceType
    true
    KeyValue
    tickerCash
    exchangeAccount
    2015-01-0100007217808a-02f5-4204-8c33-0ffb74e1e423100000NACashTransfer
    true
    KeyValue
    tickerAAPL
    exchangeNASDAQ
    2015-01-051000102.509910d8590f3b-7f8c-4795-8eaa-a01e73ce0f91-10260.9933BuyMarket
    true
    KeyValue
    tickerAAPL
    exchangeNASDAQ
    2015-10-05-900105.336410fd1bd3ec-b5fb-4a86-8521-84e9c20d9d2a9470.2776SellMarket
    1. var account = new Account("Simulation","USD", 100000.00, Context.date("2015-01-01"), new PerTradeFees(10.0));
    2. var stockdata = new StockData(new StockID("AAPL", "NASDAQ"), new MarketArchiveHttpReader());
    3. var strategy = new RSI2Strategy(stockdata);
    4. var trader = new PaperTrader(account);
    5. var state = new Fitness(trader).getFitness(strategy, account.getDateRange());
    6. // print one parameter
    7. println("Return: " + state.result().getValue(KPI.AbsoluteReturn));
    8. // print all parameters
    9. Displayers.display(state.result().getParameters())
    Return: 56741.0
    
    KeyValue
    ReturnPercentAnualized19
    NumberOfTrades5
    SharpeRatio1
    MaxDrawDownPercent33517
    PurchasedValue92884
    ReturnPurcentStdDev0
    RealizedGains-7066
    NumberOfBuys3
    TotalFees50
    AbsoluteReturn56741
    MaxDrawDownLowValue88757
    MaxDrawDownNumberOfDays458
    AbsoluteReturnAvaragePerDay74
    ActualValue156741
    MaxDrawDownHighValue122274
    AbsoluteReturnStdDev1235
    UnrealizedGains63858
    ReturnPercent57
    NumberOfTradedStocks1
    Cash97
    NumberOfCashTransfers1
    NumberOfSells2
    Displayers.display(account.getTransactions())
    
    activestockIDdatequantityrequestedPricefilledPricefeescommentidimpactOnCashbuyOrSellrequestedPriceType
    true
    KeyValue
    tickerCash
    exchangeAccount
    2015-01-0100001af70412-cea9-4c63-a3ad-5e6ba047f31b100000NACashTransfer
    true
    KeyValue
    tickerAAPL
    exchangeNASDAQ
    2015-01-129660103.4187101e16cf8a-81fb-4115-8bff-6e65abc38749-99912.458BuyMarket
    true
    KeyValue
    tickerAAPL
    exchangeNASDAQ
    2015-08-17-9660112.3154105bf75205-f175-4760-9ec9-6a8402bd5219108486.6756SellMarket
    true
    KeyValue
    tickerAAPL
    exchangeNASDAQ
    2016-04-1510200106.332310c4543d5d-108e-4383-8088-d723dab52bfd-108468.9442BuyMarket
    true
    KeyValue
    tickerAAPL
    exchangeNASDAQ
    2016-05-10-1020090.979103fbc5afb-00f2-49ca-bce4-364a77cbe0b192788.5762SellMarket
    true
    KeyValue
    tickerAAPL
    exchangeNASDAQ
    2016-08-118780105.67931058710958-a9ac-49eb-861f-9ec8b66d5988-92796.3972BuyMarket
    1. // create chart for total values
    2. var chart = new TimeSeriesChart();
    3. chart.add(account.getTotalValueHistory(), "Total Value")
    4. chart.add(account.getCashHistoryForAllDates(), "Cash")
    5. chart.add(account.getActualValueHistory(), "Actual Value")
    6. chart.addLabels(account.getTransactions())
    7. chart

    In order to get a better understanding of the development of the values over time we can
    chart the Acocunt information.

    Displayers.display(account.getTransactions())
    
    activestockIDdatequantityrequestedPricefilledPricefeescommentidimpactOnCashbuyOrSellrequestedPriceType
    true
    KeyValue
    tickerCash
    exchangeAccount
    2015-01-0100001af70412-cea9-4c63-a3ad-5e6ba047f31b100000NACashTransfer
    true
    KeyValue
    tickerAAPL
    exchangeNASDAQ
    2015-01-129660103.4187101e16cf8a-81fb-4115-8bff-6e65abc38749-99912.458BuyMarket
    true
    KeyValue
    tickerAAPL
    exchangeNASDAQ
    2015-08-17-9660112.3154105bf75205-f175-4760-9ec9-6a8402bd5219108486.6756SellMarket
    true
    KeyValue
    tickerAAPL
    exchangeNASDAQ
    2016-04-1510200106.332310c4543d5d-108e-4383-8088-d723dab52bfd-108468.9442BuyMarket
    true
    KeyValue
    tickerAAPL
    exchangeNASDAQ
    2016-05-10-1020090.979103fbc5afb-00f2-49ca-bce4-364a77cbe0b192788.5762SellMarket
    true
    KeyValue
    tickerAAPL
    exchangeNASDAQ
    2016-08-118780105.67931058710958-a9ac-49eb-861f-9ec8b66d5988-92796.3972BuyMarket

    Trading Strategies Description

    1. import scala.collection.JavaConversions._
    2. var list = new ArrayList[HashMap[String,String]]()
    3. for (strategy <- TradingStrategyFactory.list()) {
    4. var map = new HashMap[String,String]();
    5. map.put("Name", strategy)
    6. map.put("Description",TradingStrategyFactory.getStrategyDesciption(strategy))
    7. list.add(map)
    8. }
    9. Displayers.display(list)
    DescriptionName
    Developed by Donald Lambert, the Commodity Channel Index (CCI) is a momentum oscillator that can be used to identify a new trend or warn of extreme conditions. This strategy uses weekly CCI to dictate the trading bias when it surges above +100 or plunges below -100, which are key levels noted by Lambert. Once the trading bias is set, daily CCI is used to generate trading signals when it reaches its extremes.Details can be found in stockcharts

    CCICorrectionStrategy
    This strategy compares the current price to the global extrema over a week. We ar going long if the close price goes below the minimum price. We are going short if the close price goes above the maximum price.GlobalExtremaStrategy
    Many trading strategies are based on a process, not a single signal. This process often involves a series of steps that ultimately lead to a signal. Typically, chartists first establish a trading bias or long-term perspective. Second, chartists wait for pullbacks or bounces that will improve the risk-reward ratio. Third, chartists look for a reversal that indicates a subsequent upturn or downturn in price. The strategy put forth here uses moving average to define the trend, the Stochastic Oscillator to identify corrections within that trend and the MACD-Histogram to signal short-term reversals. It is a complete strategy based on a three step process.

    http://stockcharts.com/school/doku.php?id=chart_school:trading_strategies:moving_momentum

    MovingMomentumStrategy
    Developed by Larry Connors, the 2-period RSI strategy is a mean-reversion trading strategy designed to buy or sell securities after a corrective period. The strategy is rather simple. Connors suggests looking for buying opportunities when 2-period RSI moves below 10, which is considered deeply oversold. Conversely, traders can look for short-selling opportunities when 2-period RSI moves above 90. This is a rather aggressive short-term strategy designed to participate in an ongoing trend. It is not designed to identify major tops or bottoms. Before looking at the details, note that this article is designed to educate chartists on possible strategies. We are not presenting a stand-alone trading strategy that can be used right out of the box. Instead, this article is meant to enhance strategy development and refinement.
    See http://stockcharts.com/school/doku.php?id=chart_school:trading_strategies:rsi2.
    RSI2Strategy
    We buy the title when the account is opened and hold the stock. This strategy can be used as a baseline to compare the other strategies.BuyAndHoldStrategy

    Comparing Trading Strategies

    Here is a small example which compares the trading strategies for Apple starting from 2015-01-01

    1. import java.util.ArrayList
    2. def calculateResult(account:Account, strategy : IOptimizableTradingStrategy) : java.util.Map[String,Object] = {
    3. var state = new SimulatedFitness(account).getFitness(strategy, account.getDateRange());
    4. var result = state.getMap();
    5. // add strategy name to result
    6. result.put("Strategy", strategy.getClass().getSimpleName());
    7. return result;
    8. }
    9. var account = new Account("Simulation","USD", 100000.00, Context.date("2015-01-01"), new PerTradeFees(10.0));
    10. var sd = Context.getStockData("AAPL", "NASDAQ");
    11. var result = new ArrayList[java.util.Map[String,Object]]();
    12. result.add(calculateResult(account, new RSI2Strategy(sd)));
    13. result.add(calculateResult(account, new BuyAndHoldStrategy(sd)));
    14. result.add(calculateResult(account, new CCICorrectionStrategy(sd)));
    15. result.add(calculateResult(account, new GlobalExtremaStrategy(sd)));
    16. result.add(calculateResult(account, new MovingMomentumStrategy(sd)));
    17. Displayers.display(result)
    PurchasedValueSharpeRatioRealizedGainsUnrealizedGainsLongSMAPeriodCashMaxDrawDownLowValueNumberOfTradesNumberOfTradedStocksEntryLimitRSIPeriodNumberOfCashTransfersAbsoluteReturnAvaragePerDayNumberOfSellsMaxDrawDownHighValueShortSMAPeriodReturnPercentAnualizedAbsoluteReturnStdDevExitLimitAbsoluteReturnNumberOfBuysReturnPercentTotalFeesMaxDrawDownNumberOfDaysActualValueMaxDrawDownPercentReturnPurcentStdDevStrategy
    928841-7066638582009788757515217421222745191235955674135750458156741335170RSI2Strategy
    99990107236814850031119401222012416157235817210426172358371980BuyAndHoldStrategy
    794041-20566487414774745311371102875911062814522830487128145281300CCICorrectionStrategy
    13983914027901398399437144115222112952131031398392240440318139839185820GlobalExtremaStrategy
    1058850592501058858312141182106331274058852640331105885232100MovingMomentumStrategy

    Custom Trading Strategies

    Finally we demonstrate how you can implement your custom Strategy. The indicators and trading strategy functionality is based on TA4J https://github.com/ta4j/ta4j.

    The simplest and fastest way is to implement a BaseStrategy by extending the CommonTradingStrategy:

    1. import ch.pschatzmann.dates._;
    2. import ch.pschatzmann.stocks._;
    3. import ch.pschatzmann.stocks.accounting._;
    4. import ch.pschatzmann.stocks.integration._;
    5. import ch.pschatzmann.stocks.execution._;
    6. import ch.pschatzmann.stocks.execution.fees._;
    7. import ch.pschatzmann.stocks.strategy._;
    8. import ch.pschatzmann.stocks.strategy.optimization._;
    9. import ch.pschatzmann.stocks.input._;
    10. import ch.pschatzmann.stocks.parameters._;
    11. import org.ta4j.core._;
    12. import org.ta4j.core.analysis._;
    13. import org.ta4j.core.analysis.criteria._;
    14. import org.ta4j.core.indicators._;
    15. import org.ta4j.core.indicators.helpers._;
    16. import org.ta4j.core.trading.rules._;
    17. import ch.pschatzmann.display.Displayers
    18. class DemoStrategy(sd : StockData) extends CommonTradingStrategy (sd){
    19. // Define BaseStrategy
    20. def buildStrategy(timeSeries : TimeSeries) : BaseStrategy = {
    21. val closePrices = new ClosePriceIndicator(timeSeries);
    22. // Getting the max price over the past week
    23. val maxPrices = new MaxPriceIndicator(timeSeries);
    24. val weekMaxPrice = new HighestValueIndicator(maxPrices, 7);
    25. // Getting the min price over the past week
    26. val minPrices = new MinPriceIndicator(timeSeries);
    27. val weekMinPrice = new LowestValueIndicator(minPrices, 7);
    28. // Going long if the close price goes below the min price
    29. val downWeek = new MultiplierIndicator(weekMinPrice, Decimal.valueOf(1.004));
    30. val buyingRule = new UnderIndicatorRule(closePrices, downWeek);
    31. // Going short if the close price goes above the max price
    32. val upWeek = new MultiplierIndicator(weekMaxPrice, Decimal.valueOf(0.996));
    33. val sellingRule = new OverIndicatorRule(closePrices, upWeek);
    34. return new BaseStrategy(buyingRule, sellingRule);
    35. }
    36. }
    37. var apple = new StockData(new StockID("AAPL", "NASDAQ"), new MarketArchiveHttpReader());
    38. var account = new Account("Simulation","USD", 100000.00, Context.date("2015-01-01"), new PerTradeFees(10.0));
    39. var strategy = new DemoStrategy(apple);
    40. var trader = new PaperTrader(account);
    41. var state = new Fitness(trader).getFitness(strategy, account.getDateRange());
    42. //println("Return: "+state.result().getValue(KPI.AbsoluteReturn));
    43. Displayers.display(state.getMap());
    KeyValue
    AbsoluteReturnStdDev1031
    PurchasedValue139839
    SharpeRatio1
    RealizedGains40279
    AbsoluteReturn39839
    UnrealizedGains0
    NumberOfBuys22
    Cash139839
    ReturnPercent40
    MaxDrawDownLowValue94371
    TotalFees440
    MaxDrawDownNumberOfDays318
    NumberOfTrades44
    NumberOfTradedStocks1
    NumberOfCashTransfers1
    ActualValue139839
    MaxDrawDownPercent18582
    ReturnPurcentStdDev0
    AbsoluteReturnAvaragePerDay52
    NumberOfSells22
    MaxDrawDownHighValue112952
    ReturnPercentAnualized13

    An alternaive approach is to implement the interface directly:

    1. import ch.pschatzmann.dates._;
    2. import ch.pschatzmann.stocks._;
    3. import ch.pschatzmann.stocks.accounting._;
    4. import ch.pschatzmann.stocks.integration._;
    5. import ch.pschatzmann.stocks.execution._;
    6. import ch.pschatzmann.stocks.execution.fees._;
    7. import ch.pschatzmann.stocks.strategy._;
    8. import ch.pschatzmann.stocks.strategy.optimization._;
    9. import ch.pschatzmann.stocks.input._;
    10. import ch.pschatzmann.stocks.parameters._;
    11. import org.ta4j.core._;
    12. import org.ta4j.core.analysis._;
    13. import org.ta4j.core.analysis.criteria._;
    14. import org.ta4j.core.indicators._;
    15. import org.ta4j.core.indicators.helpers._;
    16. import org.ta4j.core.trading.rules._;
    17. import ch.pschatzmann.display.Displayers
    18. /**
    19. * Strategy implemented in Scala
    20. */
    21. class DemoStrategy extends ITradingStrategy {
    22. var state = new State();
    23. val stockdata = new StockData(new StockID("AAPL", "NASDAQ"), new MarketArchiveHttpReader());
    24. def getStrategy():Strategy = {
    25. var timeSeries = new Ta4jTimeSeries(getStockData());
    26. val closePrices = new ClosePriceIndicator(timeSeries);
    27. // Getting the max price over the past week
    28. val maxPrices = new MaxPriceIndicator(timeSeries);
    29. val weekMaxPrice = new HighestValueIndicator(maxPrices, 7);
    30. // Getting the min price over the past week
    31. val minPrices = new MinPriceIndicator(timeSeries);
    32. val weekMinPrice = new LowestValueIndicator(minPrices, 7);
    33. // Going long if the close price goes below the min price
    34. val downWeek = new MultiplierIndicator(weekMinPrice, Decimal.valueOf(1.004));
    35. val buyingRule = new UnderIndicatorRule(closePrices, downWeek);
    36. // Going short if the close price goes above the max price
    37. val upWeek = new MultiplierIndicator(weekMaxPrice, Decimal.valueOf(0.996));
    38. val sellingRule = new OverIndicatorRule(closePrices, upWeek);
    39. return new BaseStrategy(buyingRule, sellingRule);
    40. }
    41. def getStockData():StockData = {
    42. return stockdata;
    43. }
    44. def getName():String = {
    45. return "DemoStrategy";
    46. }
    47. def getDescription():String = {
    48. return "Demo strategy implemented in scala";
    49. }
    50. def getParameters():State = {
    51. return state;
    52. }
    53. def reset() {}
    54. }
    55. var account = new Account("Simulation","USD", 100000.00, Context.date("2015-01-01"), new PerTradeFees(10.0));
    56. var strategy = new DemoStrategy();
    57. var trader = new PaperTrader(account);
    58. var state = new Fitness(trader).getFitness(strategy,account.getDateRange());
    59. //println("Return: "+state.result().getValue(KPI.AbsoluteReturn));
    60. Displayers.display(state.getMap());
    KeyValue
    AbsoluteReturnStdDev1031
    PurchasedValue139839
    SharpeRatio1
    RealizedGains40279
    AbsoluteReturn39839
    UnrealizedGains0
    NumberOfBuys22
    Cash139839
    ReturnPercent40
    MaxDrawDownLowValue94371
    TotalFees440
    MaxDrawDownNumberOfDays318
    NumberOfTrades44
    NumberOfTradedStocks1
    NumberOfCashTransfers1
    ActualValue139839
    MaxDrawDownPercent18582
    ReturnPurcentStdDev0
    AbsoluteReturnAvaragePerDay52
    NumberOfSells22
    MaxDrawDownHighValue112952
    ReturnPercentAnualized13

    see also:

    1. Deeplearning4j – Iris Classification Example
    2. Deeplearning4j – Recurrent Neural Networks (RNN)
    3. Arduino Raspberry Pico – Looking Under the Hood
    4. Multiple Wordpess Instances in Docker with NGINX & https
    5. Docker and Treafik – A Comprehensive Tutorial
    6. Docker + WordPress = Danger
    7. Microcontrollers and MIDI – Using the Bluetooth Serial Interface
    8. Identity Management and Authentication for Java Webservices and Javascript GUIs
    9. WooCommerce und Java REST Webhooks
    10. AI Thinker AudioKit – A simple Synthesizer with STK
  • 相关阅读:
    leetcode 93: 复原IP地址 (面试常考)
    【多线程】创建线程池有几种方式
    设计资料原理图-383光纤加速计算-XCKU060的双路QSFP+光纤PCIe 卡 高速信号处理卡
    Hadoop、Hive安装
    Python 文件的读写操作
    桥接设计模式
    【编程实践】利用pcl实现点云凸包点生成
    数码管动态扫描
    CloudCompare 二次开发(15)——点云添加高斯噪声
    TDengine3.0 新架构设计思路
  • 原文地址:https://blog.csdn.net/qq_34068440/article/details/133376330