Develop Your System

This section is to discuss the key components in Cyan Spring framework and how to develop your system based on those components

Introduction

Skill requirements

Adaptor framework

Strategy framework

Tutorial

Tutorial on strategy development

We will demonstrate how to develop a single-Instrument strategy based on Cyan Spring strategy framework in this page. For multi-instrument strategies, please refer to Dollar Neutral and Low High strategies implementation included in the software distribution.


Custom Strategy - Version One

Developing an aglorithmic trading strategy is never a trivial task. However, Cyan Spring Strategy Framework has made it a lot easier. In the coming example, we are going to develop a commonly used Single Instrument Strategy called Iceberg. You will need Java programming knowledge for this. Experience with Eclipse will help but not important.


The Requirements

Iceberg strategy is useful when you have a huge order and you do not want to show all the quantity in market. Iceberg strategy will control the the release of quantity to market bit by bit. The following are the business requirements:

Writing The Codes

Assuming you have build the project successfully in Maven and your source code directory is c:\projects\algo, open the custom project, you will find 3 files:
	CustomStrategy1.java
	CustomStrategy1PriceAnalyzer.java
	CustomStrategy1QuantityAnalyzer.java
	

Open them up to take a look, they are pretty much empty. Next we are going to fill in some codes for CustomStrategy1PriceAnalyzer.java and CustomStrategy1QuantityAnalyzer.java.

For file: CustomStrategy1QuantityAnalyzer.java

	public class CustomStrategy1QuantityAnalyzer extends AbstractQuantityAnalyzer {

	@Override
	protected QuantityInstruction calculate(SingleInstrumentStrategy strategy) {
			ParentOrder order = strategy.getParentOrder();
			//retrieve display quantity
			Double disQty = order.get(Double.class, "Dis Qty");
			if(null == disQty)
				strategy.logError("Missing Dis Qty Parameter");
			
			//set passive quantity to display quantity
			QuantityInstruction qi = new QuantityInstruction();
			qi.setPassiveQty(disQty);
			return qi;
		}

	}
	

For file: CustomStrategy1PriceAnalyzer.java


	public class CustomStrategy1PriceAnalyzer extends AbstractPriceAnalyzer {

		@Override
		protected PriceInstruction calculate(QuantityInstruction qtyInstruction,
			SingleInstrumentStrategy strategy) {
			ParentOrder order = strategy.getParentOrder();
			Quote quote = strategy.getQuote();
			// setting the price to best bid for buy or best ask for sell
			double price = order.getSide().isBuy()?quote.getBid():quote.getAsk();
			PriceInstruction pi = new PriceInstruction();
			// taking the price and quantity we set and send to framework as
			// a PriceInstruction object
			pi.add(new PriceAllocation(order.getSymbol(), order.getSide(), price, qtyInstruction.getPassiveQty(), 
					ExchangeOrderType.LIMIT, strategy.getId()));
			return pi;
		}
	}
	
	

That's it! This is all you need to do. You don't get to see any order sending/receiving codes or any market data process codes because they are already taken care by the strategy framework.

XML configuration

After finishing writing the java codes, we will need to do some xml editing to tell the strategy framework how to load your strategy. we need to have a [class name].xml to put in /conf directory. In our case, the xml configuration file name is conf/CustomStrategy1.xml. You may load it up in your editor and change it to the following
	<bean id="customStrategy1" class="com.cyanspring.custom.strategy.CustomStrategy1" scope="prototype">
		<property name="strategyName" value="CUSTOM1"/>
		<property name="executionAnalyzer">
			<ref bean="defaultExecutionAnalyzer"/>
		</property>
		<property name="executionManager">
			<ref bean="defaultExecutionManager"/>
		</property>
		<property name="quantityAnalyzer">
			<bean class="com.cyanspring.custom.strategy.CustomStrategy1QuantityAnalyzer"></bean>	
		</property>
		<property name="priceAnalyzer">
			<bean class="com.cyanspring.custom.strategy.CustomStrategy1PriceAnalyzer"></bean>	
		</property>
		<property name="strategyFieldDefs">
	        <list>
            	<bean class="com.cyanspring.common.business.FieldDef">
            		<property name="name" value="Dis Qty"/>
            		<property name="type" value="java.lang.Double"/>
            		<property name="input" value="true"/>
            		<property name="amendable" value="true"/>
            		<property name="value" value="0"/>
				</bean>
	        </list>
		</property>
		
	</bean>
	
Some explanation on the strategyFieldDefs property. It takes a list of FieldDef objects and defines the strategy parameters:

Build/Deploy/Test

After finish coding, you may ran

mvn clean install

to build the custom project. When it is successfully built, take cyanspring-custom-1.53.jar from the target directory and copy it into your server/strategies directory. You should be able to enter a new single-instrument strategy with CUSTOM1 and test it with simulator.

Custom Strategy - Version Two

The vanilla Iceberg strategy that we developed in previous section is a relative passive strategy. It just sits there to wait for things happen. If market doesn't move towards us, it may become difficult to complete the order. In this section, we are going to enhance this strategy and make it a bit more aggressive.

The Requirements

We add the following in addition to version one requirements:

Adding A Strategy Parameter

The the new feature of our strategy requires a new parameter. Adding a strategy parameter can be something tedious especially where there is a chain of handling across server and clients. The good news is that Cyan Spring strategy framework has already taken care of this. It is only a matter of changing a configuration file.

Please load up conf/CustomStrategy1.xml in your editor and add the new parameter "Agg interval" shown below

	<bean id="customStrategy1" class="com.cyanspring.custom.strategy.CustomStrategy1" scope="prototype">
		<property name="strategyName" value="CUSTOM1"/>
		<property name="executionAnalyzer">
			<ref bean="defaultExecutionAnalyzer"/>
		</property>
		<property name="executionManager">
			<ref bean="defaultExecutionManager"/>
		</property>
		<property name="quantityAnalyzer">
			<bean class="com.cyanspring.custom.strategy.CustomStrategy1QuantityAnalyzer"></bean>	
		</property>
		<property name="priceAnalyzer">
			<bean class="com.cyanspring.custom.strategy.CustomStrategy1PriceAnalyzer"></bean>	
		</property>
		<property name="strategyFieldDefs">
	        <list>
            	<bean class="com.cyanspring.common.business.FieldDef">
            		<property name="name" value="Dis Qty"/>
            		<property name="type" value="java.lang.Double"/>
            		<property name="input" value="true"/>
            		<property name="amendable" value="true"/>
            		<property name="value" value="0"/>
				</bean>
            	<bean class="com.cyanspring.common.business.FieldDef">
            		<property name="name" value="Agg interval"/>
            		<property name="type" value="java.lang.Long"/>
            		<property name="input" value="false"/>
            		<property name="amendable" value="true"/>
            		<property name="value" value="15"/>
				</bean>
	        </list>
		</property>
		
	</bean>
	

You may do a quick build and deploy on project custom to test it. Open up the order entering dialog, you should find a new parameter called "Agg interval" with default value of 15


Writing The Codes

There are a bit more handling codes for our new requirements but not really much. The strategy container already provides a timer mechanism, we only need to hook our logic in.

For file: CustomStrategy1.java

	public class CustomStrategy1 extends SingleInstrumentStrategy {
		private static final Logger log = LoggerFactory
				.getLogger(CustomStrategy1.class);
		
		
		@Override
		public void processAsyncTimerEvent(AsyncTimerEvent event) {
			Long interval = parentOrder.get(Long.class, "Agg interval");
			// only apply this logic when field "Agg interval" is set and not 0
			if(null != interval && interval > 0) {
				// the time when last fill came
				Date lastExecutionTime = this.getLastExecutionTime();
				long pass = Clock.getInstance().now().getTime() - lastExecutionTime.getTime();
				if(pass >= interval * 1000)
					// execute our logic now
					execute(ExecuteTiming.NOW);
			}
			
			super.processAsyncTimerEvent(event);
		}
	}
	

Some new codes are added for CustomStrategy1PriceAnalyzer.java and CustomStrategy1QuantityAnalyzer.java.

For file: CustomStrategy1QuantityAnalyzer.java

	public class CustomStrategy1QuantityAnalyzer extends AbstractQuantityAnalyzer {

		@Override
		protected QuantityInstruction calculate(SingleInstrumentStrategy strategy) {
			ParentOrder order = strategy.getParentOrder();
			// retrieve display quantity
			Double disQty = order.get(Double.class,	"Dis Qty");
			if (null == disQty)
				strategy.logError("Missing Dis Qty Parameter");

			// set passive quantity to display quantity
			QuantityInstruction qi = new QuantityInstruction();
			qi.setPassiveQty(disQty);

			// added for version two - work out aggressive quantity
			Long interval = order.get(Long.class, "Agg interval");
			// only apply this logic when field "Agg interval" is set and not 0
			if (null != interval && interval > 0) {
				// the time when last fill came
				Date lastExecutionTime = strategy.getLastExecutionTime();
				long pass = Clock.getInstance().now().getTime()
						- lastExecutionTime.getTime();
				if (pass >= interval * 1000)
					qi.setAggresiveQty(disQty);
			}

			return qi;
		}

	}
	

For file: CustomStrategy1PriceAnalyzer.java


	public class CustomStrategy1PriceAnalyzer extends AbstractPriceAnalyzer {

		@Override
		protected PriceInstruction calculate(QuantityInstruction qtyInstruction,
				SingleInstrumentStrategy strategy) {
			ParentOrder order = strategy.getParentOrder();
			Quote quote = strategy.getQuote();
			// setting the price to best bid for buy or best ask for sell
			double price = order.getSide().isBuy() ? quote.getBid() : quote
					.getAsk();
			PriceInstruction pi = new PriceInstruction(order.getSide());
			// taking the price and quantity we set and send to framework as
			// a PriceInstruction object
			pi.add(new PriceAllocation(order.getSymbol(), order.getSide(), price,
					qtyInstruction.getPassiveQty(), ExchangeOrderType.LIMIT));

			// added for version two - work out aggressive price for aggress quantity
			if (qtyInstruction.getAggresiveQty() > 0) {
				price = order.getSide().isBuy() ? quote.getAsk() : quote.getBid();
				double qty = order.getSide().isBuy() ? quote.getAskVol() : quote
						.getBidVol();
				// since we dont want to move market much, we only take out one
				// price level of
				// far touch
				qty = Math.min(qtyInstruction.getAggresiveQty(), qty);
				pi.add(new PriceAllocation(order.getSymbol(), order.getSide(),
						price, qty, ExchangeOrderType.LIMIT));
			}
			return pi;
		}

	}
	

Build/Deploy/Test

You may rebuild project custom with "mvn clean install" and deploy the jar to test the new functionality.

Summary

We hope the above sample programs give you some ideas of how to develop strategies by using Cyan Spring strategy framework. You may get help here if you hit any issues in completing this exercise. The following are the tips for some common problems/confusions: