From aad5f77b97cb80a2c14491dff27ba0630c987e0a Mon Sep 17 00:00:00 2001 From: dazcodes Date: Mon, 4 Nov 2024 22:32:22 +0000 Subject: [PATCH 1/5] altering my logic and changing conditions to buy/sell --- .../sotw/SimpleAlgoState.java | 2 + .../gettingstarted/MyAlgoLogic.java | 124 +++++++++++++++++- .../gettingstarted/MyAlgoTest.java | 56 +++++++- 3 files changed, 171 insertions(+), 11 deletions(-) diff --git a/algo-exercise/algo/src/main/java/codingblackfemales/sotw/SimpleAlgoState.java b/algo-exercise/algo/src/main/java/codingblackfemales/sotw/SimpleAlgoState.java index b27d0972..bec37374 100644 --- a/algo-exercise/algo/src/main/java/codingblackfemales/sotw/SimpleAlgoState.java +++ b/algo-exercise/algo/src/main/java/codingblackfemales/sotw/SimpleAlgoState.java @@ -20,4 +20,6 @@ public interface SimpleAlgoState { public List getActiveChildOrders(); public long getInstrumentId(); + + } diff --git a/algo-exercise/getting-started/src/main/java/codingblackfemales/gettingstarted/MyAlgoLogic.java b/algo-exercise/getting-started/src/main/java/codingblackfemales/gettingstarted/MyAlgoLogic.java index f0259d0a..7db33569 100644 --- a/algo-exercise/getting-started/src/main/java/codingblackfemales/gettingstarted/MyAlgoLogic.java +++ b/algo-exercise/getting-started/src/main/java/codingblackfemales/gettingstarted/MyAlgoLogic.java @@ -1,10 +1,16 @@ package codingblackfemales.gettingstarted; import codingblackfemales.action.Action; +import codingblackfemales.action.CancelChildOrder; +import codingblackfemales.action.CreateChildOrder; import codingblackfemales.action.NoAction; import codingblackfemales.algo.AlgoLogic; +import codingblackfemales.sotw.ChildOrder; import codingblackfemales.sotw.SimpleAlgoState; +import codingblackfemales.sotw.marketdata.AskLevel; +import codingblackfemales.sotw.marketdata.BidLevel; import codingblackfemales.util.Util; +import messages.order.Side; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -12,19 +18,127 @@ public class MyAlgoLogic implements AlgoLogic { private static final Logger logger = LoggerFactory.getLogger(MyAlgoLogic.class); + // Thresholds for buy and sell actions based on percentage deviations + private static final double buyThreshold = -1.5; // Buy when bid is 1.5% lower than recent trades + private static final double sellThreshold = 1.5; // Sell if best ask is 1.5% higher than recent trades + private static final double spreadThreshold = -2.5; // Minimum spread threshold as a percentage ideally wanted 0.5% + + @Override public Action evaluate(SimpleAlgoState state) { var orderBookAsString = Util.orderBookToString(state); +//shows current state of order book and current state of active orders logger.info("[MYALGO] The state of the order book is:\n" + orderBookAsString); + logger.info("Active Orders:" + state.getActiveChildOrders().toString()); + + var totalOrderCount = state.getChildOrders().size(); + + //make sure we have an exit condition... + if (totalOrderCount > 10) { + return NoAction.NoAction; + } + + final BidLevel bidlevel = state.getBidAt(0); + final long bestBidPrice = bidlevel.price; + final long bidQuantity = bidlevel.quantity; + + + + final AskLevel asklevel = state.getAskAt(0); + final long bestAskPrice = asklevel.price; + final long askQuantity = asklevel.quantity; + + + + + //calculate the spread + final long spread = bestAskPrice - bestBidPrice; + logger.info("[MYALGO] Spread between ask and bid " + spread); + + //calculate the midPrice + final long midPrice =(bestBidPrice + bestBidPrice)/2; + logger.info("[MYALGO] Mid-price calculated:" + midPrice); + + //Calculate the spread as a percentage of the mid-price + final double spreadPercentage = (double) spread / midPrice * 100; + logger.info("[MYALGO] Spread percentage: " + spreadPercentage + "%"); + + + // not to create or cancel orders because spread is small + if (spreadPercentage < spreadThreshold) { + logger.info("[MYALGO] The spread is small (" + spread + "), No Action"); + return NoAction.NoAction; + + } + + //Count the buy and sell orders + + long buyOrdersCount = state.getChildOrders().stream().filter(ChildOrder -> ChildOrder.getSide() == Side.BUY).count(); + long sellOrdersCount = state.getChildOrders().stream().filter(ChildOrder -> ChildOrder.getSide() == Side.SELL).count(); - /******** - * - * Add your logic here.... - * - */ +//count the total filled quantity +// logger.info("[MYALGO] Total filled buy quantity: " + totalFilledBuyQuantity); +// logger.info("[MYALGO] Total filled sell quantity: " + totalFilledSellQuantity); + + //create new buy orders if below best bid is threshold below threshold + if (buyOrdersCount < 5 && bestBidPrice < midPrice * (1 + buyThreshold /100.0)) { + return createBuyOrder(state, buyOrdersCount, bidQuantity, bestBidPrice); + } + + //create new sell orders if price above threshold percentage + if (sellOrdersCount < 5 && bestAskPrice > midPrice * (1 + sellThreshold / 100.0)) { + return createSellOrder(state, sellOrdersCount, askQuantity, bestAskPrice); + } + + //cancel orders that don't match the best price + + return cancelOrders(state, bestBidPrice, bestAskPrice); + } + + //create method to create new bid order + public Action createBuyOrder(SimpleAlgoState state, long buyOrdersCount, long bidQuantity, long bestBidPrice) { + logger.info("[MYALGO] Creating new buy order: " + state.getChildOrders().size() + " orders and add to new buy order " + bidQuantity + " @ " + bestBidPrice); + logger.info(state.getActiveChildOrders().toString()); + logger.info("Buy order count is:" + buyOrdersCount); + //creates a new child order + return new CreateChildOrder(Side.BUY, bidQuantity, bestBidPrice); + + } + + // create a method to create a new sell order + public Action createSellOrder(SimpleAlgoState state, long sellOrdersCount, long askQuantity, long bestAskPrice) { + logger.info("[MYALGO] Creating new sell order:" + state.getChildOrders().size() + " orders and add to new sell order " + askQuantity + " @ " + bestAskPrice); + logger.info("Sell order count is:" + sellOrdersCount); + //creates a new child order + return new CreateChildOrder(Side.SELL, askQuantity, bestAskPrice); + } + + //create a method to cancel orders that don't match best price or fall below thresholds + public Action cancelOrders(SimpleAlgoState state, long bestBidPrice, long bestAskPrice){ + for (ChildOrder order : state.getActiveChildOrders()){ + logger.info("Order ID: #" + order.getOrderId() + ", Side: " + order.getSide() + ", Price: " + order.getPrice() + ", Quantity: " + order.getQuantity()); + + // Cancel buy orders not matching the best price or below the buy threshold + if (order.getSide() == Side.BUY && order.getPrice() < bestBidPrice) { + logger.info("[MYALGO] Cancel BUY order #" + order.getOrderId() + " with price " + order.getPrice()); + return new CancelChildOrder(order); + } + + // Cancel sell orders not matching the best price or below the sell threshold + if (order.getSide() == Side.SELL && order.getPrice() > bestAskPrice ) { + logger.info("[MYALGO] Cancel SELL order #" + order.getOrderId() + " with price " + order.getPrice()); + return new CancelChildOrder(order); + } + } return NoAction.NoAction; } } + + + + + + diff --git a/algo-exercise/getting-started/src/test/java/codingblackfemales/gettingstarted/MyAlgoTest.java b/algo-exercise/getting-started/src/test/java/codingblackfemales/gettingstarted/MyAlgoTest.java index c16427bb..df998d57 100644 --- a/algo-exercise/getting-started/src/test/java/codingblackfemales/gettingstarted/MyAlgoTest.java +++ b/algo-exercise/getting-started/src/test/java/codingblackfemales/gettingstarted/MyAlgoTest.java @@ -1,7 +1,22 @@ package codingblackfemales.gettingstarted; +import codingblackfemales.action.Action; +import codingblackfemales.action.NoAction; import codingblackfemales.algo.AlgoLogic; +import codingblackfemales.service.MarketDataService; +import codingblackfemales.service.OrderService; +import org.agrona.concurrent.UnsafeBuffer; +import codingblackfemales.sotw.SimpleAlgoState; +import codingblackfemales.sotw.SimpleAlgoStateImpl; +import messages.order.Side; +import org.junit.Assert; +import org.junit.Before; import org.junit.Test; +import codingblackfemales.container.RunTrigger; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + /** @@ -15,6 +30,10 @@ * */ public class MyAlgoTest extends AbstractAlgoTest { + private SimpleAlgoState algoState; + private MarketDataService marketDataService; + private OrderService orderService; + @Override public AlgoLogic createAlgoLogic() { @@ -22,14 +41,39 @@ public AlgoLogic createAlgoLogic() { return new MyAlgoLogic(); } + @Before + public void setUp() { + marketDataService = new MarketDataService(new RunTrigger()); + orderService = new OrderService(new RunTrigger()); + algoState = new SimpleAlgoStateImpl(marketDataService, orderService); + System.out.println(" MyAlgoTest"); + } + + @Test + public void testNoActionWhenSpreadIsBelowThreshold(){ + algoState.getBidAt(0). + } - @Test - public void testDispatchThroughSequencer() throws Exception { - //create a sample market data tick.... + @Test + public void testCancelSellOrders() throws Exception { send(createTick()); + send(createTick2()); + send(createTick3()); + send(createTick4()); - //simple assert to check we had 3 orders created - //assertEquals(container.getState().getChildOrders().size(), 3); + + + } + +@Test + public void testDispatchThroughSequencer () throws Exception { + + //create a sample market data tick.... + send(createTick()); + SimpleAlgoState state = container.getState(); + Action action = createAlgoLogic().evaluate(state); + assertEquals("Do not action if spread is below threshold", NoAction.NoAction, action); + } } -} + From a9d809b83bd06f860c320352f4253ba2888e190b Mon Sep 17 00:00:00 2001 From: dazcodes Date: Mon, 4 Nov 2024 23:07:16 +0000 Subject: [PATCH 2/5] altering my logic and changing conditions to buy/sell --- .../gettingstarted/MyAlgoTest.java | 17 +---------------- 1 file changed, 1 insertion(+), 16 deletions(-) diff --git a/algo-exercise/getting-started/src/test/java/codingblackfemales/gettingstarted/MyAlgoTest.java b/algo-exercise/getting-started/src/test/java/codingblackfemales/gettingstarted/MyAlgoTest.java index df998d57..6b0bc1d9 100644 --- a/algo-exercise/getting-started/src/test/java/codingblackfemales/gettingstarted/MyAlgoTest.java +++ b/algo-exercise/getting-started/src/test/java/codingblackfemales/gettingstarted/MyAlgoTest.java @@ -5,6 +5,7 @@ import codingblackfemales.algo.AlgoLogic; import codingblackfemales.service.MarketDataService; import codingblackfemales.service.OrderService; +import codingblackfemales.sotw.marketdata.BidLevel; import org.agrona.concurrent.UnsafeBuffer; import codingblackfemales.sotw.SimpleAlgoState; import codingblackfemales.sotw.SimpleAlgoStateImpl; @@ -49,22 +50,6 @@ public void setUp() { System.out.println(" MyAlgoTest"); } - @Test - public void testNoActionWhenSpreadIsBelowThreshold(){ - algoState.getBidAt(0). - } - - - @Test - public void testCancelSellOrders() throws Exception { - send(createTick()); - send(createTick2()); - send(createTick3()); - send(createTick4()); - - - - } @Test public void testDispatchThroughSequencer () throws Exception { From 2bbea31076dd754a4aaecd3f28b24a92841e5d21 Mon Sep 17 00:00:00 2001 From: dazcodes Date: Wed, 6 Nov 2024 11:34:21 +0000 Subject: [PATCH 3/5] altering my logic and changing conditions to buy/sell --- algo-exercise/getting-started/README.md | 0 .../gettingstarted/MyAlgoLogic.java | 77 +++++++++++++------ .../gettingstarted/AbstractAlgoTest.java | 67 ++++++++++++++++ .../gettingstarted/MyAlgoBackTest.java | 34 ++++++++ .../gettingstarted/MyAlgoTest.java | 60 +++++++++++++-- 5 files changed, 207 insertions(+), 31 deletions(-) create mode 100644 algo-exercise/getting-started/README.md diff --git a/algo-exercise/getting-started/README.md b/algo-exercise/getting-started/README.md new file mode 100644 index 00000000..e69de29b diff --git a/algo-exercise/getting-started/src/main/java/codingblackfemales/gettingstarted/MyAlgoLogic.java b/algo-exercise/getting-started/src/main/java/codingblackfemales/gettingstarted/MyAlgoLogic.java index 7db33569..f0d5d4eb 100644 --- a/algo-exercise/getting-started/src/main/java/codingblackfemales/gettingstarted/MyAlgoLogic.java +++ b/algo-exercise/getting-started/src/main/java/codingblackfemales/gettingstarted/MyAlgoLogic.java @@ -14,14 +14,16 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.util.Iterator; + public class MyAlgoLogic implements AlgoLogic { private static final Logger logger = LoggerFactory.getLogger(MyAlgoLogic.class); + // Thresholds for buy and sell actions + private static long buyThreshold = 90; // Minimum acceptable bid price for a buy order + private static long sellThreshold = 115; // Minimum acceptable ask price for a sell order + private static long spreadThreshold = -3; // Minimum spread threshold for action - // Thresholds for buy and sell actions based on percentage deviations - private static final double buyThreshold = -1.5; // Buy when bid is 1.5% lower than recent trades - private static final double sellThreshold = 1.5; // Sell if best ask is 1.5% higher than recent trades - private static final double spreadThreshold = -2.5; // Minimum spread threshold as a percentage ideally wanted 0.5% @Override @@ -40,6 +42,8 @@ public Action evaluate(SimpleAlgoState state) { return NoAction.NoAction; } + + final BidLevel bidlevel = state.getBidAt(0); final long bestBidPrice = bidlevel.price; final long bidQuantity = bidlevel.quantity; @@ -51,8 +55,6 @@ public Action evaluate(SimpleAlgoState state) { final long askQuantity = asklevel.quantity; - - //calculate the spread final long spread = bestAskPrice - bestBidPrice; logger.info("[MYALGO] Spread between ask and bid " + spread); @@ -65,30 +67,32 @@ public Action evaluate(SimpleAlgoState state) { final double spreadPercentage = (double) spread / midPrice * 100; logger.info("[MYALGO] Spread percentage: " + spreadPercentage + "%"); + // Check for matching orders + matchOrders(state, bestBidPrice, bestAskPrice); + + // not to create or cancel orders because spread is small - if (spreadPercentage < spreadThreshold) { - logger.info("[MYALGO] The spread is small (" + spread + "), No Action"); + if (spread < spreadThreshold) { + logger.info("[MYALGO] The spread is small " + spread + " No Action"); return NoAction.NoAction; } - //Count the buy and sell orders +//count the buy and sell orders long buyOrdersCount = state.getChildOrders().stream().filter(ChildOrder -> ChildOrder.getSide() == Side.BUY).count(); long sellOrdersCount = state.getChildOrders().stream().filter(ChildOrder -> ChildOrder.getSide() == Side.SELL).count(); -//count the total filled quantity -// logger.info("[MYALGO] Total filled buy quantity: " + totalFilledBuyQuantity); -// logger.info("[MYALGO] Total filled sell quantity: " + totalFilledSellQuantity); - //create new buy orders if below best bid is threshold below threshold - if (buyOrdersCount < 5 && bestBidPrice < midPrice * (1 + buyThreshold /100.0)) { + + //create new buy orders if there are less than 5 orders + if (buyOrdersCount < 5 ) { return createBuyOrder(state, buyOrdersCount, bidQuantity, bestBidPrice); } - //create new sell orders if price above threshold percentage - if (sellOrdersCount < 5 && bestAskPrice > midPrice * (1 + sellThreshold / 100.0)) { + //create new sell orders if there are less than 5 order + if (sellOrdersCount < 5 ) { return createSellOrder(state, sellOrdersCount, askQuantity, bestAskPrice); } @@ -97,7 +101,26 @@ public Action evaluate(SimpleAlgoState state) { return cancelOrders(state, bestBidPrice, bestAskPrice); } - //create method to create new bid order + private void matchOrders(SimpleAlgoState state, long bestBidPrice, long bestAskPrice) { + Iterator iterator = state.getActiveChildOrders().iterator(); + + while (iterator.hasNext()) { + ChildOrder order = iterator.next(); + if (order.getSide() == Side.BUY && order.getPrice() >= bestAskPrice) { + logger.info("[MYALGO] Matched BUY order: Order ID: #" + order.getOrderId() +", Side: " + order.getSide() + ", Price: " + order.getPrice() + ", Quantity: " + order.getQuantity()); + iterator.remove(); // Remove matched order + } else if (order.getSide() == Side.SELL && order.getPrice() <= bestBidPrice) { + logger.info("[MYALGO] Matched SELL order: Order ID: #" + order.getOrderId() +", Side: " + order.getSide() + ", Price: " + order.getPrice() + ", Quantity: " + order.getQuantity()); + iterator.remove(); // Remove matched order + } + } + } + + + + + + //create method to create new buy order public Action createBuyOrder(SimpleAlgoState state, long buyOrdersCount, long bidQuantity, long bestBidPrice) { logger.info("[MYALGO] Creating new buy order: " + state.getChildOrders().size() + " orders and add to new buy order " + bidQuantity + " @ " + bestBidPrice); logger.info(state.getActiveChildOrders().toString()); @@ -120,15 +143,25 @@ public Action cancelOrders(SimpleAlgoState state, long bestBidPrice, long bestAs for (ChildOrder order : state.getActiveChildOrders()){ logger.info("Order ID: #" + order.getOrderId() + ", Side: " + order.getSide() + ", Price: " + order.getPrice() + ", Quantity: " + order.getQuantity()); + boolean buyOrder = order.getSide() ==Side.BUY; + boolean notBuyThreshold = order.getPrice() != buyThreshold; + boolean lessThanBuyThreshold = order.getPrice() < buyThreshold; + // Cancel buy orders not matching the best price or below the buy threshold - if (order.getSide() == Side.BUY && order.getPrice() < bestBidPrice) { - logger.info("[MYALGO] Cancel BUY order #" + order.getOrderId() + " with price " + order.getPrice()); + if (buyOrder && (notBuyThreshold || lessThanBuyThreshold)) { + logger.info(String.format("The buy Threshold is %d", + buyThreshold )); + logger.info(String.format("[MYALGO] Cancel BUY order %d with price %d and quantity %d. The current best bid price is %d." ,+ order.getOrderId(), + order.getPrice(), + order.getQuantity(), + bestBidPrice)); return new CancelChildOrder(order); } + boolean sellTheOrder = order.getSide() ==Side.SELL; + boolean notSellThreshold = order.getPrice() != sellThreshold; + boolean lessThanSellThreshold = order.getPrice() < sellThreshold; + // Cancel sell orders not matching the best price or below the sell threshold - if (order.getSide() == Side.SELL && order.getPrice() > bestAskPrice ) { - logger.info("[MYALGO] Cancel SELL order #" + order.getOrderId() + " with price " + order.getPrice()); + if (sellTheOrder && (notSellThreshold || lessThanSellThreshold)) { + logger.info(String.format("The sell Threshold is %d", + sellThreshold )); + logger.info(String.format("[MYALGO] Cancel SELL order %d with price %d and quantity %d. The current best ask price is %d." ,+ order.getOrderId(), + order.getPrice(), + order.getQuantity(), + bestAskPrice)); return new CancelChildOrder(order); } } @@ -140,5 +173,3 @@ public Action cancelOrders(SimpleAlgoState state, long bestBidPrice, long bestAs - - diff --git a/algo-exercise/getting-started/src/test/java/codingblackfemales/gettingstarted/AbstractAlgoTest.java b/algo-exercise/getting-started/src/test/java/codingblackfemales/gettingstarted/AbstractAlgoTest.java index f57fef15..7db0e8f3 100644 --- a/algo-exercise/getting-started/src/test/java/codingblackfemales/gettingstarted/AbstractAlgoTest.java +++ b/algo-exercise/getting-started/src/test/java/codingblackfemales/gettingstarted/AbstractAlgoTest.java @@ -75,6 +75,73 @@ protected UnsafeBuffer createTick(){ return directBuffer; } + protected UnsafeBuffer createTickWithHighThreshold() { + final MessageHeaderEncoder headerEncoder = new MessageHeaderEncoder(); + final BookUpdateEncoder encoder = new BookUpdateEncoder(); + final ByteBuffer byteBuffer = ByteBuffer.allocateDirect(1024); + final UnsafeBuffer directBuffer = new UnsafeBuffer(byteBuffer); + + // Encode the message + encoder.wrapAndApplyHeader(directBuffer, 0, headerEncoder); + + // Set a high spread by configuring ask and bid levels + encoder.venue(Venue.XLON); + encoder.instrumentId(123L); + + // Here, we’ll set a very high ask and a much lower bid. + encoder.askBookCount(1).next().price(150L).size(300L); // High ask price + encoder.bidBookCount(1).next().price(100L).size(300L); // Low bid price + + encoder.instrumentStatus(InstrumentStatus.CONTINUOUS); + encoder.source(Source.STREAM); + + return directBuffer; + } + + protected UnsafeBuffer createTickWithLowThreshold() { + final MessageHeaderEncoder headerEncoder = new MessageHeaderEncoder(); + final BookUpdateEncoder encoder = new BookUpdateEncoder(); + final ByteBuffer byteBuffer = ByteBuffer.allocateDirect(1024); + final UnsafeBuffer directBuffer = new UnsafeBuffer(byteBuffer); + + encoder.wrapAndApplyHeader(directBuffer, 0, headerEncoder); + encoder.venue(Venue.XLON); + encoder.instrumentId(123L); + + encoder.askBookCount(1) + .next().price(100L).size(200L); // Ask price close to bid + + encoder.bidBookCount(1) + .next().price(90L).size(200L); // Bid price close to ask + + encoder.instrumentStatus(InstrumentStatus.CONTINUOUS); + encoder.source(Source.STREAM); + + return directBuffer; + } + + protected UnsafeBuffer createTickWithIncreasingVolume() { + final MessageHeaderEncoder headerEncoder = new MessageHeaderEncoder(); + final BookUpdateEncoder encoder = new BookUpdateEncoder(); + final ByteBuffer byteBuffer = ByteBuffer.allocateDirect(1024); + final UnsafeBuffer directBuffer = new UnsafeBuffer(byteBuffer); + + encoder.wrapAndApplyHeader(directBuffer, 0, headerEncoder); + encoder.venue(Venue.XLON); + encoder.instrumentId(123L); + + encoder.askBookCount(1) + .next().price(110L).size(1000L); // Higher ask quantity + + encoder.bidBookCount(1) + .next().price(108L).size(900L); // Higher bid quantity + + encoder.instrumentStatus(InstrumentStatus.CONTINUOUS); + encoder.source(Source.STREAM); + + return directBuffer; + } + } diff --git a/algo-exercise/getting-started/src/test/java/codingblackfemales/gettingstarted/MyAlgoBackTest.java b/algo-exercise/getting-started/src/test/java/codingblackfemales/gettingstarted/MyAlgoBackTest.java index 1c1b3fd7..7ff75c75 100644 --- a/algo-exercise/getting-started/src/test/java/codingblackfemales/gettingstarted/MyAlgoBackTest.java +++ b/algo-exercise/getting-started/src/test/java/codingblackfemales/gettingstarted/MyAlgoBackTest.java @@ -1,8 +1,13 @@ package codingblackfemales.gettingstarted; import codingblackfemales.algo.AlgoLogic; +import codingblackfemales.sotw.ChildOrder; +import messages.order.Side; +import org.junit.Before; import org.junit.Test; +import static org.junit.Assert.*; + /** * This test plugs together all of the infrastructure, including the order book (which you can trade against) * and the market data feed. @@ -22,6 +27,14 @@ public AlgoLogic createAlgoLogic() { return new MyAlgoLogic(); } + + @Before + + public void setup() { + container.getState().getChildOrders().clear(); + + } + @Test public void testExampleBackTest() throws Exception { //create a sample market data tick.... @@ -42,4 +55,25 @@ public void testExampleBackTest() throws Exception { //assertEquals(225, filledQuantity); } + @Test public void testForOrderManagement () throws Exception{ + send(createTick()); + send(createTick2()); + + //check algo has a max order limit of 10 + assertTrue("There should be at least 10 child orders", container.getState().getChildOrders().size() <=10 ); + } + +// @Test +// +// public void testCancelOrders () throws Exception{ +// for (int i = 0; i< 5; i++){ +// container.getState().getChildOrders().add(new ChildOrder(Side.BUY, 500L + i, 110, 115, i + 1)); +// send(createTick2()); +// assertEquals(10, container.getState().getChildOrders().size()); +// ChildOrder cancelOrders = container.getState().getChildOrders().stream().filter(order -> order.getState() == 2).findFirst().orElse(null); +// System.out.println("Check if there are cancelled orders. Found: " + (cancelOrders != null)); +// assertEquals(true, cancelOrders != null); +// +// } +// } } diff --git a/algo-exercise/getting-started/src/test/java/codingblackfemales/gettingstarted/MyAlgoTest.java b/algo-exercise/getting-started/src/test/java/codingblackfemales/gettingstarted/MyAlgoTest.java index 6b0bc1d9..68e42a04 100644 --- a/algo-exercise/getting-started/src/test/java/codingblackfemales/gettingstarted/MyAlgoTest.java +++ b/algo-exercise/getting-started/src/test/java/codingblackfemales/gettingstarted/MyAlgoTest.java @@ -1,6 +1,7 @@ package codingblackfemales.gettingstarted; import codingblackfemales.action.Action; +import codingblackfemales.action.CreateChildOrder; import codingblackfemales.action.NoAction; import codingblackfemales.algo.AlgoLogic; import codingblackfemales.service.MarketDataService; @@ -51,14 +52,57 @@ public void setUp() { } -@Test - public void testDispatchThroughSequencer () throws Exception { + @Test + public void testDispatchThroughSequencer() throws Exception { - //create a sample market data tick.... - send(createTick()); - SimpleAlgoState state = container.getState(); - Action action = createAlgoLogic().evaluate(state); - assertEquals("Do not action if spread is below threshold", NoAction.NoAction, action); - } + //create a sample market data tick.... + send(createTick()); + + + SimpleAlgoState state = container.getState(); + Action action = createAlgoLogic().evaluate(state); + assertEquals("Do not action if spread is below threshold", NoAction.NoAction, action); + } + + @Test + public void testCancelOrderOnLowThreshold() throws Exception { + // Send tick with low spread + send(createTickWithLowThreshold()); + SimpleAlgoState state = container.getState(); + Action action = createAlgoLogic().evaluate(state); + + // Check that no action is taken if spread is too low for orders + assertTrue("Expected NoAction when spread is below threshold", action instanceof NoAction); } + + @Test + public void testHandleIncreasingVolume() throws Exception { + // Arrange: Set up a tick with increasing bid/ask volume + send(createTickWithIncreasingVolume()); + SimpleAlgoState state = container.getState(); + + // Act: Evaluate the state after the high-volume tick + Action action = createAlgoLogic().evaluate(state); + + // Assert: Check that algo reacts appropriately to the high-volume tick + assertTrue("Expected NoAction or appropriate order response on high volume", action instanceof Action); + } + + @Test + public void testCreateOrderWithHighThreshold() throws Exception { + // Arrange: Send a tick with a high spread + send(createTickWithHighThreshold()); + } + + @Test + public void testMaxOrders() throws Exception { + send(createTick()); + + //check algo has a max order limit of 10 + assertTrue("There should be at least 10 child orders", container.getState().getChildOrders().size() <= 10); + } +} + + + From 20136d6d8977f13b09393655f68068dde9868aa8 Mon Sep 17 00:00:00 2001 From: Daz_codes <85360799+dazcodes@users.noreply.github.com> Date: Wed, 6 Nov 2024 12:17:30 +0000 Subject: [PATCH 4/5] Update README.md creating readme about my project --- algo-exercise/getting-started/README.md | 43 +++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/algo-exercise/getting-started/README.md b/algo-exercise/getting-started/README.md index e69de29b..a77a56cb 100644 --- a/algo-exercise/getting-started/README.md +++ b/algo-exercise/getting-started/README.md @@ -0,0 +1,43 @@ +# Coding Black Females - My Trading Algorithm Application + +### Overview +This project is a Java- based trading algorithm designed to automate decision making in the financial markets. The algorithm does this by analysing the order and executing buy and sell actions based on market conditions. The project aims to simplify trading operations by automatically managing orders, this helps users to make timely trading decisions without manual intervention. The main problem it addresses is the need for efficient and rule-based order management in fast-moving markets. It reduces human error by automating repetitive tasks like matching buy and sell orders, creating new orders based on specific conditions, and cancelling orders that no longer meet the criteria. This type of automation is particularly valuable for traders who want to capitalise on market opportunities quickly while adhering to a pre-defined strategy. + +This project is useful because it enhances trading efficiency by using predefined thresholds and actions to guide decision-making. The algorithm’s logging system also provides real-time insights into its operations, which helps in monitoring performance and refining trading strategies. My project offers an extendable framework starting point for developers and traders interested in creating or optimising algorithmic trading solutions. + +### How to Get Started + +#### Pre-requisites + +1. The project requires Java version 17 or higher + +##### Note +This project is configured for Java 17. If you have a later version installed, it will compile and run successfully, but you may see warnings in the log like this, which you can safely ignore: + +```sh +[WARNING] system modules path not set in conjunction with -source 17 +``` + +#### Opening the project + +1. Fork this repo in GitHub and clone it to your local machine +2. Open the project as a Maven project in your IDE (normally by opening the top level pom.xml file) +3. Click to expand the "getting-started" module + +##### Note +You will first need to run the Maven `install` task to make sure the binary encoders and decoders are installed and available for use. You can use the provided Maven wrapper or an installed instance of Maven, either in the command line or from the IDE integration. + +To get started, run the following command from the project root: `./mvnw clean install`. Once you've done this, you can compile or test specific projects using the `--projects` flag, e.g.: + +- Clean all projects: `./mvnw clean` +- Test all `algo-exercise` projects: `./mvnw test --projects algo-exercise` +- Compile the `getting-started` project only: `./mvnw compile --projects algo-exercise/getting-started` +- Then run the Algotest/ AlgoBacktest to see the output of my code + + ☺️ 💻 + + + + + + From 2f394e4a3e91a78630a399b9e43799cf33290027 Mon Sep 17 00:00:00 2001 From: Daz_codes <85360799+dazcodes@users.noreply.github.com> Date: Wed, 6 Nov 2024 16:28:23 +0000 Subject: [PATCH 5/5] Update README.md