Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixes #84 - TradingStrategy as Spring bean #85

Merged
merged 2 commits into from
Jan 2, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.stereotype.Component;

Expand Down Expand Up @@ -153,6 +154,8 @@ public class TradingEngine {
private final StrategyConfigService strategyConfigService;
private final MarketConfigService marketConfigService;

@Autowired
private ApplicationContext springContext;

@Autowired
public TradingEngine(ExchangeConfigService exchangeConfigService, EngineConfigService engineConfigService,
Expand Down Expand Up @@ -573,7 +576,6 @@ private void loadMarketConfigAndInitialiseTradingStrategies() {

if (strategyDescriptions.containsKey(strategyToUse)) {
final StrategyConfig tradingStrategy = strategyDescriptions.get(strategyToUse);
final String tradingStrategyClassname = tradingStrategy.getClassName();

// Grab optional config for the Trading Strategy
final StrategyConfigItems tradingStrategyConfig = new StrategyConfigItems();
Expand All @@ -590,7 +592,7 @@ private void loadMarketConfigAndInitialiseTradingStrategies() {
* Load the Trading Strategy impl, instantiate it, set its config, and store in the cached
* Trading Strategy execution list.
*/
final TradingStrategy strategyImpl = ConfigurableComponentFactory.createComponent(tradingStrategyClassname);
TradingStrategy strategyImpl = obtainTradingStrategyInstance(tradingStrategy);;
strategyImpl.init(exchangeAdapter, tradingMarket, tradingStrategyConfig);

LOG.info(() -> "Initialized trading strategy successfully. Name: [" + tradingStrategy.getName()
Expand All @@ -610,4 +612,27 @@ private void loadMarketConfigAndInitialiseTradingStrategies() {

LOG.info(() -> "Loaded and set Market configuration successfully!");
}

private TradingStrategy obtainTradingStrategyInstance(StrategyConfig tradingStrategy) {
final String tradingStrategyClassname = tradingStrategy.getClassName();
final String tradingStrategyBeanName = tradingStrategy.getBeanName();

TradingStrategy strategyImpl = null;
if (tradingStrategyBeanName != null) {
// if beanName is configured, try get the bean first
try {
strategyImpl = (TradingStrategy) springContext.getBean(tradingStrategyBeanName);

} catch (NullPointerException e) {
final String errorMsg = "Failed to obtain bean [ "+tradingStrategyBeanName+"] from spring context";
LOG.error(errorMsg);
throw new IllegalArgumentException(errorMsg);
}
}
if (strategyImpl == null) {
// if beanName not configured use className
strategyImpl = ConfigurableComponentFactory.createComponent(tradingStrategyClassname);
}
return strategyImpl;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ private enum EngineState {
private static final String STRATEGY_NAME = "MACD Shorting algo";
private static final String STRATEGY_DESCRIPTION = "MACD Shorting algo description";
private static final String STRATEGY_IMPL_CLASS = "com.my.strats.MyMacdStrategy";
private static final String STRATEGY_IMPL_BEAN = null;
private static final String STRATEGY_CONFIG_ITEM_NAME = "btc-sell-order-amount";
private static final String STRATEGY_CONFIG_ITEM_VALUE = "0.2";

Expand Down Expand Up @@ -601,7 +602,7 @@ private static List<StrategyConfig> allTheStrategiesConfig() {
configItems.put(STRATEGY_CONFIG_ITEM_NAME, STRATEGY_CONFIG_ITEM_VALUE);

final StrategyConfig strategyConfig1 = new StrategyConfig(
STRATEGY_ID, STRATEGY_NAME, STRATEGY_DESCRIPTION, STRATEGY_IMPL_CLASS, configItems);
STRATEGY_ID, STRATEGY_NAME, STRATEGY_DESCRIPTION, STRATEGY_IMPL_CLASS, STRATEGY_IMPL_BEAN, configItems);

final List<StrategyConfig> allStrategies = new ArrayList<>();
allStrategies.add(strategyConfig1);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ public class StrategyConfig {
private String name;
private String description;
private String className;
private String beanName;
private Map<String, String> configItems = new HashMap<>();


Expand All @@ -52,14 +53,16 @@ public StrategyConfig(StrategyConfig other) {
this.name = other.name;
this.description = other.description;
this.className = other.className;
this.beanName = other.beanName;
this.configItems = other.configItems;
}

public StrategyConfig(String id, String name, String description, String className, Map<String, String> configItems) {
public StrategyConfig(String id, String name, String description, String className, String beanName, Map<String, String> configItems) {
this.id = id;
this.name = name;
this.description = description;
this.className = className;
this.beanName = beanName;
this.configItems = configItems;
}

Expand Down Expand Up @@ -95,6 +98,14 @@ public void setClassName(String className) {
this.className = className;
}

public String getBeanName() {
return beanName;
}

public void setBeanName(String beanName) {
this.beanName = beanName;
}

public Map<String, String> getConfigItems() {
return configItems;
}
Expand Down Expand Up @@ -123,6 +134,7 @@ public String toString() {
.add("name", name)
.add("description", description)
.add("className", className)
.add("beanName", beanName)
.add("configItems", configItems)
.toString();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,13 +42,14 @@ public class TestStrategyConfig {
private static final String LABEL = "MACD Long Position Algo";
private static final String DESCRIPTION = "Uses MACD as indicator and takes long position in base currency.";
private static final String CLASSNAME = "com.gazbert.nova.algos.MacdLongBase";
private static final String BEANNAME = "macdLongBase";
private static final Map<String, String> CONFIG_ITEMS = new HashMap<>();


@Test
public void testInitialisationWorksAsExpected() {

final StrategyConfig strategyConfig = new StrategyConfig(ID, LABEL, DESCRIPTION, CLASSNAME, CONFIG_ITEMS);
final StrategyConfig strategyConfig = new StrategyConfig(ID, LABEL, DESCRIPTION, CLASSNAME, BEANNAME, CONFIG_ITEMS);
assertEquals(ID, strategyConfig.getId());
assertEquals(LABEL, strategyConfig.getName());
assertEquals(DESCRIPTION, strategyConfig.getDescription());
Expand Down Expand Up @@ -84,7 +85,7 @@ public void testSettersWorkAsExpected() {

@Test
public void testCloningWorksAsExpected() {
final StrategyConfig strategyConfig = new StrategyConfig(ID, LABEL, DESCRIPTION, CLASSNAME, CONFIG_ITEMS);
final StrategyConfig strategyConfig = new StrategyConfig(ID, LABEL, DESCRIPTION, CLASSNAME, BEANNAME, CONFIG_ITEMS);
final StrategyConfig clonedStrategyConfig = new StrategyConfig(strategyConfig);
assertEquals(clonedStrategyConfig, strategyConfig);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,7 @@ private static List<StrategyConfig> adaptAllInternalToAllExternalConfig(TradingS
strategyConfig.setName(item.getName());
strategyConfig.setDescription(item.getDescription());
strategyConfig.setClassName(item.getClassName());
strategyConfig.setBeanName(item.getBeanName());

item.getOptionalConfig().getConfigItem().forEach(internalConfigItem ->
strategyConfig.getConfigItems().put(internalConfigItem.getName(), internalConfigItem.getValue()));
Expand All @@ -215,6 +216,8 @@ private static StrategyConfig adaptInternalToExternalConfig(List<StrategyType> i
strategyConfig.setName(internalStrategyConfig.getName());
strategyConfig.setDescription(internalStrategyConfig.getDescription());
strategyConfig.setClassName(internalStrategyConfig.getClassName());
strategyConfig.setBeanName(internalStrategyConfig.getBeanName());


internalStrategyConfig.getOptionalConfig().getConfigItem().forEach(internalConfigItem ->
strategyConfig.getConfigItems().put(internalConfigItem.getName(), internalConfigItem.getValue()));
Expand All @@ -239,6 +242,7 @@ private static StrategyType adaptExternalToInternalConfig(StrategyConfig externa
strategyType.setName(externalStrategyConfig.getName());
strategyType.setDescription(externalStrategyConfig.getDescription());
strategyType.setClassName(externalStrategyConfig.getClassName());
strategyType.setBeanName(externalStrategyConfig.getBeanName());
strategyType.setOptionalConfig(configurationType);
return strategyType;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,11 +67,13 @@ public class TestStrategyConfigRepository {
private static final String STRAT_NAME_1 = "MACD Long Position Algo";
private static final String STRAT_DESCRIPTION_1 = "Uses MACD as indicator and takes long position in base currency.";
private static final String STRAT_CLASSNAME_1 = "com.gazbert.nova.algos.MacdLongBase";
private static final String STRAT_BEANAME_1 = "macdLongBase";

private static final String STRAT_ID_2 = "long-scalper";
private static final String STRAT_NAME_2 = "Long Position Scalper Algo";
private static final String STRAT_DESCRIPTION_2 = "Scalps and goes long...";
private static final String STRAT_CLASSNAME_2 = "com.gazbert.nova.algos.LongScalper";
private static final String STRAT_BEANAME_2 = "longScalper";

private static final String NEW_STRAT_NAME = "Short Position Scalper Algo";
private static final String NEW_STRAT_DESCRIPTION = "Scalps and goes short...";
Expand Down Expand Up @@ -385,20 +387,20 @@ private static StrategyConfig someExternalStrategyConfig() {
final Map<String, String> configItems = new HashMap<>();
configItems.put(BUY_PRICE_CONFIG_ITEM_KEY, BUY_PRICE_CONFIG_ITEM_VALUE);
configItems.put(AMOUNT_TO_BUY_CONFIG_ITEM_KEY, AMOUNT_TO_BUY_CONFIG_ITEM_VALUE);
return new StrategyConfig(STRAT_ID_1, STRAT_NAME_1, STRAT_DESCRIPTION_1, STRAT_CLASSNAME_1, configItems);
return new StrategyConfig(STRAT_ID_1, STRAT_NAME_1, STRAT_DESCRIPTION_1, STRAT_CLASSNAME_1, STRAT_BEANAME_1, configItems);
}

private static StrategyConfig someNewExternalStrategyConfig() {
final Map<String, String> configItems = new HashMap<>();
configItems.put(BUY_PRICE_CONFIG_ITEM_KEY, BUY_PRICE_CONFIG_ITEM_VALUE);
configItems.put(AMOUNT_TO_BUY_CONFIG_ITEM_KEY, AMOUNT_TO_BUY_CONFIG_ITEM_VALUE);
return new StrategyConfig(null, NEW_STRAT_NAME, NEW_STRAT_DESCRIPTION, NEW_STRAT_CLASSNAME, configItems);
return new StrategyConfig(null, NEW_STRAT_NAME, NEW_STRAT_DESCRIPTION, NEW_STRAT_CLASSNAME, STRAT_BEANAME_2, configItems);
}

private static StrategyConfig someExternalStrategyConfigWithUnknownId() {
final Map<String, String> configItems = new HashMap<>();
configItems.put(BUY_PRICE_CONFIG_ITEM_KEY, BUY_PRICE_CONFIG_ITEM_VALUE);
configItems.put(AMOUNT_TO_BUY_CONFIG_ITEM_KEY, AMOUNT_TO_BUY_CONFIG_ITEM_VALUE);
return new StrategyConfig(UNKNOWN_STRAT_ID, STRAT_NAME_1, STRAT_DESCRIPTION_1, STRAT_CLASSNAME_1, configItems);
return new StrategyConfig(UNKNOWN_STRAT_ID, STRAT_NAME_1, STRAT_DESCRIPTION_1, STRAT_CLASSNAME_1, STRAT_BEANAME_1,configItems);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -71,11 +71,13 @@ public class TestStrategyConfigController extends AbstractConfigControllerTest {
private static final String STRAT_1_NAME = "MACD Strat Algo";
private static final String STRAT_1_DESCRIPTION = "Uses MACD as indicator and takes long position in base currency.";
private static final String STRAT_1_CLASSNAME = "com.gazbert.nova.algos.MacdLongBase";
private static final String STRAT_1_BEANNAME = "macdLongBase";

private static final String STRAT_2_ID = "long-scalper";
private static final String STRAT_2_NAME = "Long Position Scalper Algo";
private static final String STRAT_2_DESCRIPTION = "Scalps and goes long...";
private static final String STRAT_2_CLASSNAME = "com.gazbert.nova.algos.LongScalper";
private static final String STRAT_2_BEANNAME = "longScalper";

private static final String BUY_PRICE_CONFIG_ITEM_KEY = "buy-price";
private static final String BUY_PRICE_CONFIG_ITEM_VALUE = "671.15";
Expand Down Expand Up @@ -341,8 +343,8 @@ private static List<StrategyConfig> allTheStrategiesConfig() {
configItems.put(BUY_PRICE_CONFIG_ITEM_KEY, BUY_PRICE_CONFIG_ITEM_VALUE);
configItems.put(AMOUNT_TO_BUY_CONFIG_ITEM_KEY, AMOUNT_TO_BUY_CONFIG_ITEM_VALUE);

final StrategyConfig strategyConfig1 = new StrategyConfig(STRAT_1_ID, STRAT_1_NAME, STRAT_1_DESCRIPTION, STRAT_1_CLASSNAME, configItems);
final StrategyConfig strategyConfig2 = new StrategyConfig(STRAT_2_ID, STRAT_2_NAME, STRAT_2_DESCRIPTION, STRAT_2_CLASSNAME, configItems);
final StrategyConfig strategyConfig1 = new StrategyConfig(STRAT_1_ID, STRAT_1_NAME, STRAT_1_DESCRIPTION, STRAT_1_CLASSNAME, STRAT_1_BEANNAME, configItems);
final StrategyConfig strategyConfig2 = new StrategyConfig(STRAT_2_ID, STRAT_2_NAME, STRAT_2_DESCRIPTION, STRAT_2_CLASSNAME, STRAT_2_BEANNAME, configItems);

final List<StrategyConfig> allStrategies = new ArrayList<>();
allStrategies.add(strategyConfig1);
Expand All @@ -354,20 +356,20 @@ private static StrategyConfig someStrategyConfig() {
final Map<String, String> configItems = new HashMap<>();
configItems.put(BUY_PRICE_CONFIG_ITEM_KEY, BUY_PRICE_CONFIG_ITEM_VALUE);
configItems.put(AMOUNT_TO_BUY_CONFIG_ITEM_KEY, AMOUNT_TO_BUY_CONFIG_ITEM_VALUE);
return new StrategyConfig(STRAT_1_ID, STRAT_1_NAME, STRAT_1_DESCRIPTION, STRAT_1_CLASSNAME, configItems);
return new StrategyConfig(STRAT_1_ID, STRAT_1_NAME, STRAT_1_DESCRIPTION, STRAT_1_CLASSNAME, STRAT_1_BEANNAME, configItems);
}

private static StrategyConfig someStrategyConfigWithMissingId() {
final Map<String, String> configItems = new HashMap<>();
configItems.put(BUY_PRICE_CONFIG_ITEM_KEY, BUY_PRICE_CONFIG_ITEM_VALUE);
configItems.put(AMOUNT_TO_BUY_CONFIG_ITEM_KEY, AMOUNT_TO_BUY_CONFIG_ITEM_VALUE);
return new StrategyConfig(null, STRAT_1_NAME, STRAT_1_DESCRIPTION, STRAT_1_CLASSNAME, configItems);
return new StrategyConfig(null, STRAT_1_NAME, STRAT_1_DESCRIPTION, STRAT_1_CLASSNAME, STRAT_1_BEANNAME, configItems);
}

private static StrategyConfig unrecognizedStrategyConfig() {
final Map<String, String> configItems = new HashMap<>();
configItems.put(BUY_PRICE_CONFIG_ITEM_KEY, BUY_PRICE_CONFIG_ITEM_VALUE);
configItems.put(AMOUNT_TO_BUY_CONFIG_ITEM_KEY, AMOUNT_TO_BUY_CONFIG_ITEM_VALUE);
return new StrategyConfig(UNKNOWN_STRAT_ID, STRAT_1_NAME, STRAT_1_DESCRIPTION, STRAT_1_CLASSNAME, configItems);
return new StrategyConfig(UNKNOWN_STRAT_ID, STRAT_1_NAME, STRAT_1_DESCRIPTION, STRAT_1_CLASSNAME, STRAT_1_BEANNAME, configItems);
}
}
10 changes: 10 additions & 0 deletions bxbot-strategies/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,16 @@
<!--
3rd party dependencies
-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,9 @@
import com.google.common.base.MoreObjects;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.DecimalFormat;
Expand Down Expand Up @@ -115,6 +117,7 @@
*
* @author gazbert
*/
@Component("exampleScalpingStrategy")
public class ExampleScalpingStrategy implements TradingStrategy {

private static final Logger LOG = LogManager.getLogger();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,11 +58,12 @@
*/
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "strategyType", propOrder = {
"id",
"name",
"description",
"className",
"optionalConfig"
"id",
"name",
"description",
"className",
"beanName",
"optionalConfig"
})
public class StrategyType {

Expand All @@ -73,6 +74,8 @@ public class StrategyType {
protected String description;
@XmlElement(name = "class-name", required = true)
protected String className;
@XmlElement(name = "bean-name")
protected String beanName;
@XmlElement(name = "optional-config")
protected OptionalConfigType optionalConfig;

Expand Down Expand Up @@ -160,6 +163,18 @@ public String getClassName() {
return className;
}

/**
* Gets the value of the beanName property.
*
* @return
* possible object is
* {@link String }
*
*/
public String getBeanName() {
return beanName;
}

/**
* Sets the value of the className property.
*
Expand All @@ -172,6 +187,19 @@ public void setClassName(String value) {
this.className = value;
}

/**
* Sets the value of the beanName property.
*
* @param value
* allowed object is
* {@link String }
*
*/
public void setBeanName(String value) {
this.beanName = value;
}


/**
* Gets the value of the optionalConfig property.
*
Expand Down
Binary file not shown.
Binary file modified config/strategies.xml
Binary file not shown.