All Downloads are FREE. Search and download functionalities are using the official Maven repository.

ta.TaLibSignalStrategy.kt Maven / Gradle / Ivy

/*
 * Copyright 2021 Neural Layer
 *
 * 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
 *
 *     https://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.
 */

@file:Suppress("unused", "WildcardImport")

package org.roboquant.ta

import org.roboquant.common.Asset
import org.roboquant.common.Logging
import org.roboquant.common.addNotNull
import org.roboquant.common.severe
import org.roboquant.feeds.Event
import org.roboquant.feeds.PriceBar
import org.roboquant.strategies.Rating
import org.roboquant.strategies.Signal
import org.roboquant.strategies.SignalType
import org.roboquant.strategies.Strategy
import org.roboquant.strategies.utils.PriceBarSeries
import java.lang.Integer.max
import java.util.logging.Logger

/**
 * This strategy that makes it easy to implement different types strategies based on technical analysis indicators from
 * the TaLib library.
 *
 * This strategy requires [PriceBar] data and common use cases are candlestick patterns and moving average strategies.
 *
 * It is important that the strategy is initialized with a large enough [history] window to support the underlying
 * technical indicators you want to use. If the [history] is too small, it will lead to a runtime exception.
 *
 */
class TaLibSignalStrategy(
    private val history: Int = 15,
    private var block: TaLib.(series: PriceBarSeries) -> Signal?
) : Strategy {

    private val buffers = mutableMapOf()
    private val logger: Logger = Logging.getLogger(TaLibSignalStrategy::class)
    val taLib = TaLib()


    companion object {

        fun breakout(entryPeriod: Int = 100, exitPeriod: Int = 50): TaLibSignalStrategy {
            val maxPeriod = max(entryPeriod, exitPeriod)
            return TaLibSignalStrategy(maxPeriod) { series ->
                when {
                    recordHigh(series.high, entryPeriod) -> Signal(series.asset, Rating.BUY, SignalType.BOTH)
                    recordLow(series.low, entryPeriod) -> Signal(series.asset, Rating.SELL, SignalType.BOTH)
                    recordLow(series.low, exitPeriod) -> Signal(series.asset, Rating.SELL, SignalType.EXIT)
                    recordHigh(series.high, exitPeriod) -> Signal(series.asset, Rating.BUY, SignalType.EXIT)
                    else -> null
                }
            }

        }


    }


    /**
     * Based on a [event], return zero or more signals. Typically, they are for the assets in the event,
     * but this is not a strict requirement.
     *
     * @see Strategy.generate
     *
     */
    override fun generate(event: Event): List {
        val signals = mutableListOf()
        for (priceAction in event.prices.values.filterIsInstance()) {
            val asset = priceAction.asset
            val buffer = buffers.getOrPut(asset) { PriceBarSeries(asset, history) }
            if (buffer.add(priceAction)) {
                try {
                    val signal = block.invoke(taLib, buffer)
                    signals.addNotNull(signal)
                } catch (e: InsufficientData) {
                    logger.severe(
                        "Not enough data available to calculate the indicators, increase the history size",
                        e
                    )
                    throw e
                }
            }
        }
        return signals
    }

    override fun reset() {
        buffers.clear()
    }


    override fun toString() = "TaLibSignalStrategy history=$history"

}





© 2015 - 2025 Weber Informatics LLC | Privacy Policy