/**
* The MIT License (MIT)
*
* Copyright (c) 2014-2017 Marc de Verdelhan & respective authors (see AUTHORS)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package eu.verdelhan.ta4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* A trading strategy.
* <p>
* A strategy is a pair of complementary {@link Rule rules}. It may recommend to enter or to exit.
* Recommendations are based respectively on the entry rule or on the exit rule.
*/
public class Strategy {
/** The logger */
protected final Logger log = LoggerFactory.getLogger(getClass());
/** The entry rule */
private Rule entryRule;
/** The exit rule */
private Rule exitRule;
/**
* The unstable period (number of ticks).<br>
* During the unstable period of the strategy any order placement will be cancelled.<br>
* I.e. no entry/exit signal will be fired before index == unstablePeriod.
*/
private int unstablePeriod;
/**
* Constructor.
* @param entryRule the entry rule
* @param exitRule the exit rule
*/
public Strategy(Rule entryRule, Rule exitRule) {
if (entryRule == null || exitRule == null) {
throw new IllegalArgumentException("Rules cannot be null");
}
this.entryRule = entryRule;
this.exitRule = exitRule;
}
/**
* @param index a tick index
* @return true if this strategy is unstable at the provided index, false otherwise (stable)
*/
public boolean isUnstableAt(int index) {
return index < unstablePeriod;
}
/**
* @param unstablePeriod number of ticks that will be strip off for this strategy
*/
public void setUnstablePeriod(int unstablePeriod) {
this.unstablePeriod = unstablePeriod;
}
/**
* @param index the tick index
* @param tradingRecord the potentially needed trading history
* @return true to recommend an order, false otherwise (no recommendation)
*/
public boolean shouldOperate(int index, TradingRecord tradingRecord) {
Trade trade = tradingRecord.getCurrentTrade();
if (trade.isNew()) {
return shouldEnter(index, tradingRecord);
} else if (trade.isOpened()) {
return shouldExit(index, tradingRecord);
}
return false;
}
/**
* @param index the tick index
* @return true to recommend to enter, false otherwise
*/
public boolean shouldEnter(int index) {
return shouldEnter(index, null);
}
/**
* @param index the tick index
* @param tradingRecord the potentially needed trading history
* @return true to recommend to enter, false otherwise
*/
public boolean shouldEnter(int index, TradingRecord tradingRecord) {
if (isUnstableAt(index)) {
return false;
}
final boolean enter = entryRule.isSatisfied(index, tradingRecord);
traceShouldEnter(index, enter);
return enter;
}
/**
* @param index the tick index
* @return true to recommend to exit, false otherwise
*/
public boolean shouldExit(int index) {
return shouldExit(index, null);
}
/**
* @param index the tick index
* @param tradingRecord the potentially needed trading history
* @return true to recommend to exit, false otherwise
*/
public boolean shouldExit(int index, TradingRecord tradingRecord) {
if (isUnstableAt(index)) {
return false;
}
final boolean exit = exitRule.isSatisfied(index, tradingRecord);
traceShouldExit(index, exit);
return exit;
}
/**
* Traces the shouldEnter() method calls.
* @param index the tick index
* @param enter true if the strategy should enter, false otherwise
*/
protected void traceShouldEnter(int index, boolean enter) {
log.trace(">>> {}#shouldEnter({}): {}", getClass().getSimpleName(), index, enter);
}
/**
* Traces the shouldExit() method calls.
* @param index the tick index
* @param exit true if the strategy should exit, false otherwise
*/
protected void traceShouldExit(int index, boolean exit) {
log.trace(">>> {}#shouldExit({}): {}", getClass().getSimpleName(), index, exit);
}
}