OrderMan - Ordering interface for NOW + Amibroker

Snake.Head

Well-Known Member
I downloaded latest code from Github today.

Case 1.
Axisbank opened and went down, then started rising. It was howevering around 527.85
I clicked a New order 'SL' at trigger price 528.0 Stop 527 and target 0
Order Trigered at 9:38:21 for 528.05 when Axisbank rose above 528.
Orderman immediately sold the share at 527.8 and closed the trade

Case 2. At 10:53, Axisbank was going down It was around 527.9. I changed STOP_ORDER_TYPE := "SLM" to STOP_ORDER_TYPE := "SL".
Entry for Sale at 527.8 Order Type 'SL'
Stop at 529
Target 0
Orderman complained "STOP Order Type 'SL' is invalid"

Case 3. Changed STOP_ORDER_TYPE := "SL" to STOP_ORDER_TYPE := "SLM"
Entry for Sale at 527.8 Order Type 'SL'
Stop at 529
Target 0
Sale executed at 527.75
Stop executed at 527.80.
Message " Trade Closed Verify"
Those are very close price for entry and stop
Their should be around 0.50 - 1 point difference between entry and stoploss

Edit: Price very close their are buyer/seller with best five ask/bid
 
Last edited:

josh1

Well-Known Member
Those are very close price for entry and stop
Their should be around 0.50 - 1 point difference between entry and stoploss

Edit: Price very close their are buyer/seller with best five ask/bid
There is more than 0.5 point difference in both cases. Read my post again. This is Axisbank Equity. Avg. Volumes are more than 50 lakh shares. Buyer/seller with best five ask/bid nowhere near Stop.
In any case trade should not be executed above or below SL.

You have not understood my point ....
In first case, I entered New buy order at 528. my Stop was at 527(1 point below) but it executed at 527.8
In case 3, I entered New Sale order at 527.8, my Stop was at 529 (1.2 points above) but it executed at 527.8
 
Last edited:

TracerBullet

Well-Known Member
I downloaded latest code from Github today.

Case 1.
Axisbank opened and went down, then started rising. It was howevering around 527.85
I clicked a New order 'SL' at trigger price 528.0 Stop 527 and target 0
Order Trigered at 9:38:21 for 528.05 when Axisbank rose above 528.
Orderman immediately sold the share at 527.8 and closed the trade

Case 2. At 10:53, Axisbank was going down It was around 527.9. I changed STOP_ORDER_TYPE := "SLM" to STOP_ORDER_TYPE := "SL".
Entry for Sale at 527.8 Order Type 'SL'
Stop at 529
Target 0
Orderman complained "STOP Order Type 'SL' is invalid"

Case 3. Changed STOP_ORDER_TYPE := "SL" to STOP_ORDER_TYPE := "SLM"
Entry for Sale at 527.8 Order Type 'SL'
Stop at 529
Target 0
Sale executed at 527.75
Stop executed at 527.80.
Message " Trade Closed Verify"

Note: I do not see 'SLM' type of order in NOW. However, when I type SLM in OrderType, it goes to SL.
Do you mean you dont have "SL-M" option in NOW? Then thats the issue. as it tries to set SL-M which fails and maybe uses default Limit which triggers immediately.

Lets have a look after market say using ammy admin. ping me id and time.
 

josh1

Well-Known Member
Do you mean you dont have "SL-M" option in NOW? Then thats the issue. as it tries to set SL-M which fails and maybe uses default Limit which triggers immediately.

Lets have a look after market say using ammy admin. ping me id and time.
Okay.

I don't have SL-M order in NOW.
 

TracerBullet

Well-Known Member
Okay.

I don't have SL-M order in NOW.
ok, i guess your broker does not allow market orders. With Zerodha + now, i have it. If you are using SASOnline, i think they enable Market orders if you email them.

Just for reference, Attach screenshot of what options you see in Buy/Sell Order window in NOW.
SL - ok, I need to add SL-Limit option in Trade.ahk : _setupStopOrderInput(). Once done you should be able to use it - Make sure to set large MaxSlippage so that it always get filled. Will try to add separate MaxSlippage for stop.
 

Snake.Head

Well-Known Member
ok, i guess your broker does not allow market orders. With Zerodha + now, i have it. If you are using SASOnline, i think they enable Market orders if you email them.

Just for reference, Attach screenshot of what options you see in Buy/Sell Order window in NOW.
SL - ok, I need to add SL-Limit option in Trade.ahk : _setupStopOrderInput(). Once done you should be able to use it - Make sure to set large MaxSlippage so that it always get filled. Will try to add separate MaxSlippage for stop.
When you update orderman next build give option stoploss ordertype in OrderMan.ini
So that ppl with SLM can change ordertype from their

eg:
EntryOrderType = SLM
StoplossType = SL
ProfitType = L
 

TracerBullet

Well-Known Member
When you update orderman next build give option stoploss ordertype in OrderMan.ini
So that ppl with SLM can change ordertype from their

eg:
EntryOrderType = SLM
StoplossType = SL
ProfitType = L
Intention of SLL Stops will only be to be an alternative to SLM - with wide LIMIT and Trigger price difference making sure that Stop gets filled.

There wont be any additional logic to handle Slipped Stop orders.
 

josh1

Well-Known Member
I made some changes in Trade.ahk. It is working now. I remember 4 changes :lol: . I put remarks against them. TB, Please bear with me. Code is attached. Please see If I missed something.

Orderman is entering Price = 0 in SL order. This is treated as SL-M order by NOW. See below image.


My only concern is that, after execution of entry is detected, Orderman enters Stop order immediately instead of waiting for the price to reach there. This may make it easier for big Auto traders to hunt stoploss.


Code:
/*
  Copyright (C) 2015  SpiffSpaceman

  This program is free software: you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation, either version 3 of the License, or
  any later version.

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with this program.  If not, see <http://www.gnu.org/licenses/>
*/

class TradeClass{
	
	scrip			 := ""
	direction		 := ""													// B/S
	
	newEntryOrder	 := -1
	stopOrder  		 := -1
	target		 	 := new TargetClass
	
	isStopPending 	 := false												// Is Stop Waiting for Entry/Add order to trigger?
	positionSize	 := 0													// Open Position Size
	averageEntryPrice := 0													// Average Entry Price for completed orders weighted by qty

	executedEntryOrderList := []											// List of executed entry/add orders
																			// entryOrder contains details of current unexecuted order shown in GUI and _entryOrderList has all of executed orders
	
	
	
	/*	open new Trade by creating Entry/Stop/Target orders	
	*/
	create( inScrip, entryOrderType, stopOrderType, direction, qty, prodType, entryPrice, stopPrice, targetPrice, targetQty ){
	
		if ( this.positionSize == 0 && !this._checkOpenOrderEmpty() )
			return
		
		this.scrip  	:= inScrip
		this.direction	:= direction
		
		this.newEntryOrder := new OrderClass
		this._setupEntryOrderInput( entryOrderType, qty, prodType, entryPrice, direction, inScrip )
		this.newEntryOrder.create()											// Create Entry Order and update Details from Orderbook
		
		if( ! this.newEntryOrder.isCreated  )
			return
		
		isNewStopPending  := this._isStopPending( entryOrderType )
		stopDirection	  := UtilClass.reverseDirection(direction)
		
		if( this.stopOrder.isCreated   ){										
			
			this._setStopPrice( stopPrice )										// 1) Already have a position - update its stop price
			if( !isNewStopPending) {											// 2) If Add order stop is not pending, increase existing stop size	
				this._mergeStopSize()												// Else it will be set as pending below and merged when entry trigger				
			}
			
			this.stopOrder.update()
		}
		else{																	// Stop order not yet created => This is Stop for initial Entry order
																				// 	When adding, we will always have stop of Existing position			
			this.stopOrder 	:= new OrderClass									// Create Stop Order. Keep it pending if entry waiting for trigger		
			this._setupStopOrderInput(  stopOrderType,  qty, prodType, stopPrice, stopDirection, inScrip )
			if( !isNewStopPending )
				this.stopOrder.create()
		}

		this.isStopPending := isNewStopPending									// Just mark as pending. Actual Size of Pending Stop will be set when triggered
		
		this.target.handleTargetOrder( targetPrice, targetQty, this.stopOrder, this.positionSize )

		this.save()
		updateStatus()
	}
	
	/*	Update Trade - Update Entry/Stop/Target orders			
	*/
	update( inScrip, entryOrderType, stopOrderType, qty, prodType, entryPrice, stopPrice, targetPrice, targetQty  ){
				
		if( this.isNewEntryLinked() && entryPrice != "" ){		
			
			orderDirection  := this.newEntryOrder.getGUIDirection()				// same direction as linked order			
			this._setupEntryOrderInput( entryOrderType, qty, prodType, entryPrice, orderDirection, inScrip )
			this.newEntryOrder.update()
		}
		
		this._updateStop( inScrip, stopOrderType, qty, prodType, stopPrice )
		
		if( targetPrice !=-1 )													// -1 indicates no change. Else create/delete target order
			this.target.handleTargetOrder( targetPrice, targetQty, this.stopOrder, this.positionSize )

		this.save()	
		updateStatus()
	}
		
	/*	Called by Tracker Thread - orderStatusTracker()
		Create pending SL order when entry completes
		Handle Target-Stop OCO
		Handle Stop update after Target partial fill
	*/
	trackerCallback(){

		if( this.newEntryOrder.isClosed() ){									// Entry Finished

			if( this.isEntrySuccessful()  ){									// Entry Successful - Add Entry Order to Position by inserting in executedEntryOrderList

				if( this.isStopPending )										// We have pending stop order - Create/Update Stop order if Entry was successful
					this._triggerPendingStop()

				this.averageEntryPrice := this._getAveragePrice( this.positionSize, this.averageEntryPrice, this.newEntryOrder.getOrderDetails() )
				this.positionSize 	   += this.newEntryOrder.getOrderDetails().totalQty
				this.executedEntryOrderList.Push( this.newEntryOrder )

				this.target.onEntrySuccessful( this.stopOrder, this.positionSize )
																				// If Entry successful, update target order - Increase target order size
			}
			else{																// Entry Order Failed
				if( this.isStopPending  ){
					this.isStopPending := false
					MsgBox, 262144,,  Breakout Entry Order has failed. Pending stop cancelled
				}
				else{
					if( this.isEntryOrderExecuted() ){							// LIMIT/Market Order Failed - Reduce Stop Qty
						this._updateStopSize()									// Reset stop size to current position size, without entryOrder
						this.stopOrder.update()
						MsgBox, 262144,, Entry/Add Order Failed. Stop order has been reverted
					}
					else{														// Position empty, cancel stop order
						if( this.stopOrder.cancel() )
							MsgBox, 262144,, Entry/Add Order Failed. Stop order has been cancelled
						else
							MsgBox, 262144,, Entry/Add Order Failed. Stop order cancellation failed
					}
				}
			}

			this.newEntryOrder := -1 											// Unlink Entry Order to allow adds
			this.save()
		}

		if( this.stopOrder.isClosed() ){										// Stop hit/cancelled, close all open orders
			this.onTradeClose()
			return
		}
		
		targetOrder := this.target.getOpenOrder()
		if( targetOrder.isClosed() ){
			this.positionSize -= targetOrder.getFilledQty()						// Target Executed, Reduce position size
			this._updateStopSize()												// Update Stop size. If position closed, stop size will be 0 which will cancel the order in update()
			this.stopOrder.update()
			
			this.target.onTargetClose()											// Notify Open target order closure
			this.save()

			if(this.positionSize <= 0 ){										// Position closed, cancel all open orders
				this.onTradeClose()
				return
			}
		}
		else{																	// If Target LIMIT order is filled partially, update stop order
			filledQty := this.target.isPartiallyFilled()
			if( filledQty > 0  ){
				this.positionSize -= filledQty									// Reduce Position size and update Stop qty
				this._updateStopSize()
				this.stopOrder.update()
			}
		}
	}

	/* Close orders if open and unlink
	*/
	onTradeClose(){																// OCO Stop, Target Order
		entry  := this.isNewEntryLinked() ? this.newEntryOrder.cancel() : true	// If position closed, then cancel Add order if open
		stop   := this.stopOrder.cancel()
		target := this.isTargetLinked()   ? this.target.cancel() : true
		
		if( !entry || !stop || !target )
			MsgBox, 262144,, Trade Closed - OCO Failed
		else
			MsgBox, 262144,, Trade Closed - Verify
		this.unlinkOrders()														// Unlink After close
	}
	
	/*	cancel open orders - Entry/Stop/Pending Stop
		Executed orders cannot be cancelled - so no change in TargetOrder
	*/
	cancel(){
		
		if( this.isEntrySuccessful() ){										// Should never happen
			MsgBox, % 262144+4,,  Entry Order has already been Executed. Do you still want to cancel Stop order?
				IfMsgBox No
					return -1	
		}	
		
		toggleStatusTracker( "off" )										// Turn off tracker before cancelling orders
		
		if( this.isNewEntryLinked() ){
			if( ! this.newEntryOrder.cancel() ){
				toggleStatusTracker( "on" )
				MsgBox, 262144,, Entry cancellation failed
				return
			}
			this.newEntryOrder := -1
		}

		if( this.isStopLinked() ){
			if( this.isEntryOrderExecuted() ){								// Reduce Stop size to size of executed orders
				this.stopOrder.setInputQty( this.positionSize )
				this.stopOrder.update()				
			}
			else{
				if( ! this.stopOrder.cancel() ){
					toggleStatusTracker( "on" )
					MsgBox, 262144,, Entry cancellation failed
					return
				}
				this.stopOrder := -1				
			}
		}
		
		this.isStopPending  := false
		
		this.save()
		updateStatus()
	}
			
	/*	Save linked order nos to ini
		Used on startup to link to open orders on last exit
		Format:		Alias:EntryOpenOrderNo:StopOrderNo,isPending,PendingPrice:ExecutedEntryList:TargetOrderNo,TargetPrice:ExecutedTargetList
	*/
	save(){
		scripAlias	:= this.scrip.alias
		entryOrder	:= this.newEntryOrder.getOrderDetails().nowOrderNo
		stopString	:= this.stopOrder.getOrderDetails().nowOrderNo . ( "," . this.isStopPending . "," . this.stopOrder.getInput().trigger )
		
		executedEntryString := ""
		For index, value in this.executedEntryOrderList{
			executedEntryString := executedEntryString . value.getOrderDetails().nowOrderNo . ","
		}
		
		targetString 		 := this.target.getOpenOrder().getOrderDetails().nowOrderNo	. "," .  this.target.getPrice() . "," . this.target.getGUIQty()
		executedTargetString := this.target.getExecutedOrderList()
		
		savestring  := scripAlias . ":" . entryOrder . ":" . stopstring . ":" . executedEntryString . ":" . targetString . ":" . executedTargetString

		saveOrders( savestring )			
	}
	
	/* Format:		Alias:EntryOpenOrderNo:StopOrderNo,isPending,PendingPrice:ExecutedEntryList:TargetOrderNo,TargetPrice:ExecutedTargetList
	*/
	loadOrders(){
		global SavedOrders, orderbookObj
				
		orderbookObj.read()
		
		fields 					 := StrSplit( SavedOrders , ":") 
		scripAlias				 := fields[1]
		entryOrderID			 := fields[2]
		stopstring   			 := fields[3]
		executedEntryOrderIDList := fields[4]
		targetString 			 := fields[5]
		executedTargetOrderList  := fields[6]
		
		fields 	     := StrSplit( stopstring , ",")
		stopOrderID  := fields[1]
		isPending    := fields[2]
		pendingPrice := fields[3]
		
		fields		  := StrSplit( targetString , ",")
		targetOrderID := fields[1]
		_targetPrice  := fields[2]
		_targetQty	  := fields[3]
				
		return this.linkOrders( true, scripAlias, entryOrderID, executedEntryOrderIDList, stopOrderID, isPending, pendingPrice, targetOrderID, _targetPrice, _targetQty, executedTargetOrderList  )		
	}

	/*	Link with Input Order
		Linking Stop Order is optional
		Does not call this.save() - should be called by caller. loadOrders()->linkOrders() does not need to save
	*/
	linkOrders( isSilent, scripAlias, entryOrderID, executedEntryOrderIDList, stopOrderID, isPending, pendingPrice, targetOrderID, targetPrice, targetQty, executedTargetOrderList ){
		global orderbookObj, STOP_ORDER_TYPE
		
		orderbookObj.read()
		entryOrderDetails   	:= orderbookObj.getOrderDetails( entryOrderID )
		stopOrderDetails    	:= orderbookObj.getOrderDetails( stopOrderID )
		targetOrderDetails  	:= orderbookObj.getOrderDetails( targetOrderID )
		
		newEntryOrderExists 	:= IsObject(entryOrderDetails)
		stopOrderExists			:= IsObject(stopOrderDetails)
		openTargetOrderExists	:= IsObject(targetOrderDetails)
		
		newEntrySize 			:= newEntryOrderExists ? entryOrderDetails.totalQty : 0
		stopSize	 			:= stopOrderDetails.totalQty
		
		if( newEntryOrderExists && stopOrderExists && entryOrderDetails.tradingSymbol != stopOrderDetails.tradingSymbol ){
			UtilClass.conditionalMessage(isSilent, "Trading Symbol does not match for Entry and Stop Order"  ) 					
			return false
		}

		positionSize 	 	 := 0
		entryOrderListObj    := []
		targetOrderListObj   := []
		openTargetSize		 := openTargetOrderExists ? targetOrderDetails.totalQty : 0
		openTargetFilledSize := openTargetOrderExists ? targetOrderDetails.totalQty - targetOrderDetails.pendingQty : 0

		if( executedEntryOrderIDList != ""){										// Fetch Executed Entry Orders
																					// Stop will always exits if atleast 1 entry order has been filled
			size := this._loadExecutedOrders( isSilent, executedEntryOrderIDList, entryOrderListObj, stopOrderDetails.tradingSymbol  )
			if(  size == -1 )
				return false
			else
				positionSize += size
		}

		if( executedTargetOrderList != ""){											// Fetch Executed Target Orders		
			size := this._loadExecutedOrders( isSilent, executedTargetOrderList, targetOrderListObj, stopOrderDetails.tradingSymbol  )
			if(  size == -1 )
				return false
			else
				positionSize -= size												// Reduce position size
		}
		
		if( openTargetFilledSize > 0  )												// Partial Target Fill - Reduce Position size
			positionSize -= openTargetFilledSize

	// Validations
		if( isPending && !entryOrderDetails.isOpen() ){								// If Pending stop, then entry order must be open
			UtilClass.conditionalMessage(isSilent, "Entry Order is not Open" )
			return false
		}
		if( openTargetSize > positionSize ){										// Target and Entry Order size mismatch
			UtilClass.conditionalMessage(isSilent, "Target total qty exceeds Entry Position" )
			return false
		}
		if( positionSize > 0 ){														// If some entry/add orders are complete, then stop must be open
			if( !stopOrderDetails.isOpen() ){										// Should never happen with manual linking from link button
				UtilClass.conditionalMessage(isSilent, "Stop Order is not Open"  )
				return false
			}
			expectedStopSize := isPending ? positionSize : positionSize + newEntrySize			
			if( stopSize != expectedStopSize){
				UtilClass.conditionalMessage(isSilent, "Stop Size does not match with Entry position size"  )
				return false	
			}
		}
		if( positionSize == 0 ){													// If no executed orders, then entry must exist. Also stop should be open or pending
			if( !newEntryOrderExists ){												// Cannot have Open Target Order
				UtilClass.conditionalMessage(isSilent, "Order " . entryOrderID " Not found" )
				return false
			}
			if( isPending && stopOrderExists ) {
				UtilClass.conditionalMessage(isSilent, "No Entry position linked against stop order" )
				return false
			}
			if( !isPending &&  !stopOrderDetails.isOpen() ){
				UtilClass.conditionalMessage(isSilent, "No Pending/Open Stop Order Found covering Entry" )
				return false
			}
			if( !isPending &&  newEntrySize != stopSize ){
				UtilClass.conditionalMessage(isSilent, "Stop Size does not match with Entry size"  )
				return false
			}
			if( openTargetOrderExists || executedTargetOrderList != "" ){
				UtilClass.conditionalMessage(isSilent, "Cannot link Target Order without some completed Entry Orders"  )
				return false
			}
		}	

	// Validations over - Load Data

		loadScrip( scripAlias )
		
		this.newEntryOrder := new OrderClass
		this.newEntryOrder.loadOrderFromOrderbook( entryOrderDetails )
		this.executedEntryOrderList  := entryOrderListObj
		
		this.stopOrder := new OrderClass
		this.stopOrder.loadOrderFromOrderbook( stopOrderDetails )
		
		this.target.loadTarget( targetOrderDetails )
		this.target.executedOrderList := targetOrderListObj

		this._calculateAveragePrice()
		this.positionSize := positionSize

		if( !newEntryOrderExists ){													// No New Order => We may have Executed Entry Orders 
			o := this._getLastExecutedInputOrder()									// Use the latest Executed Order and copy Input to prepare for future Adds
			if( IsObject(o) ){
				o.loadOrderFromOrderbook( 0 )										// Load input from Orderbook, passing 0 
				i := o.getInput()
				this.newEntryOrder.setOrderInput( i.orderType, i.direction, i.qty, i.price, i.trigger, i.prodType, i.scrip )
			}
		}
		if( isPending ){
			this.isStopPending := true
			entryInput		   := this.newEntryOrder.getInput()
			
			if( pendingPrice == 0 && stopOrderExists)								// In manual Linking, use stop order price as pending price
				pendingPrice := this.stopOrder.getInput().trigger
			this._setupStopOrderInput( STOP_ORDER_TYPE,  entryInput.qty, entryInput.prodType, pendingPrice,  UtilClass.reverseDirection(entryInput.direction), entryInput.scrip )
		}

		this.scrip 		 := this.newEntryOrder.getInput().scrip
		this.direction 	 := this.newEntryOrder.getInput().direction

		if( ! openTargetOrderExists  && (targetPrice > 0 || targetQty > 0) ){		// Set up pending Target Order
			this.target.handleTargetOrder( targetPrice, targetQty, this.stopOrder, this.positionSize )
		}

		return true
	}

	/*	Reset All Order pointers
	*/
	unlinkOrders(){
		
		this.newEntryOrder	:= -1												// Current Entry/Add order - Not yet executed
		this.stopOrder 		:= -1												// Single stop order covering all executed orders + open entryOrder
		this.target.unlink()
		
		this.isStopPending			:= false									// Is Stop pending for entryOrder to Complete - Applicable for SL/SL M orders
		this.positionSize   		:= 0										// Sum of all successfully executed Orders' qty
		this.averageEntryPrice 		:= 0
		this.executedEntryOrderList := []										// List of successfully executed Orders		
		
		this.save()
		
		setDefaultQty()															// Reset Qty in GUI to Default Size
		setDefaultEntryOrderType()												// Reset to default order type
	}
	
	/* Reload order details from orderbook
	*/
	reload(){
		global orderbookObj
		
		orderbookObj.read()
		if( this.isNewEntryLinked() )
			this.newEntryOrder.reloadDetails()
		if( this.isStopLinked() )
			this.stopOrder.reloadDetails()
		if( this.isTargetLinked() )
			this.target.getOpenOrder().reloadDetails()
	}



	/*	New Entry Order Open ? - Returns true if newEntryOrder is an object and is linked with an order in orderbook
	*/
	isNewEntryLinked(){		
		return IsObject( this.newEntryOrder )  && IsObject(this.newEntryOrder.getOrderDetails()) 
	}
	
	/*	Returns true if atleast one Entry order has been executed - ie we have open position
	*/
	isEntryOrderExecuted(){
		return  this.positionSize > 0
	}
	
	/*	Returns true if stopOrder is an object and is linked with an order in orderbook
	*/
	isStopLinked(){		
		return IsObject( this.stopOrder ) && IsObject(this.stopOrder.getOrderDetails()) 
	}

	isTargetLinked(){
		return this.target.isLinked()
	}

	/*	Indicates whether Entry Order has status = complete
		Note this wont remain true for too long. trackerCallback will move succesful order to executedEntryOrderList.
		This is meant for use in callback
	*/
	isEntrySuccessful(){		
		return  IsObject( this.newEntryOrder ) && this.newEntryOrder.isComplete()
	}

	/*	Indicates whether Stop Order has status = complete
	*/
	isStopSuccessful(){
		return  IsObject( this.stopOrder ) && this.stopOrder.isComplete()
	}

	/*	Indicates whether Entry Order is in Order Book > Open Orders	
	*/
	isEntryOpen(){
		return  IsObject( this.newEntryOrder ) && this.newEntryOrder.isOpen()
	}
	
	/*	Indicates whether Stop Order  is in Order Book > Open Orders	
	*/
	isStopOpen(){
		return  IsObject( this.stopOrder ) && this.stopOrder.isOpen()
	}

	/*	Indicates whether Entry Order is in Order Book > Completed Orders	
	*/
	isEntryClosed(){
		return  IsObject( this.newEntryOrder ) && this.newEntryOrder.isClosed()
	}
	
	/*	Indicates whether Entry Order is in Order Book > Completed Orders	
	*/
	isStopClosed(){
		return  IsObject( this.stopOrder ) && this.stopOrder.isClosed()
	}

	/* Is Trade Direction = Long?
	*/
	isLong(){
		return this.direction == "B"
	}


// -- Private ---

	_triggerPendingStop(){

		this._mergeStopSize()

		if( this.stopOrder.isCreated ){										// If stop order already exists ( ie Entry Order was an add order )
			this.stopOrder.update()											//	  then take added qty from entry order and add to stop order
		}
		else{			
			this.stopOrder.create()			
		}
		this.isStopPending := false
		this.save()		
	}
	
	/* Take added qty from entry order and add to stop order	 
	 * Stop size = Executed Orders + Current open order
	 * positionSize will be 0 when there is no Existing position
	*/
	_mergeStopSize(){
		openEntrySize := this.newEntryOrder.getOrderDetails().totalQty
		if( openEntrySize == "" )
			openEntrySize := 0 
		this.stopOrder.getInput().qty := this.positionSize + openEntrySize
	}

	/* Update Stop size after change to positionSize
	*/
	_updateStopSize(){
		openEntrySize := this.newEntryOrder.getOrderDetails().totalQty
		if( openEntrySize == "" || this.newEntryOrder.isClosed() )
			openEntrySize := 0 
		
		this.stopOrder.getInput().qty := this.positionSize + (this.isStopPending ? 0 : openEntrySize)
	}

	/*	Set Entry Order Input details based on Order Type
	*/
	_setupEntryOrderInput( entryOrderType, qty, prodType, entryPrice, direction, scrip ){
		global MaxSlippage, ORDER_TYPE_GUI_LIMIT, ORDER_TYPE_GUI_MARKET, ORDER_TYPE_GUI_SL_MARKET, ORDER_TYPE_GUI_SL_LIMIT
		
		if( !IsObject( this.newEntryOrder ) )
			this.newEntryOrder := new OrderClass
				
		if( entryOrderType == ORDER_TYPE_GUI_LIMIT ){
			this.newEntryOrder.setOrderInput( entryOrderType, direction, qty, entryPrice, 0, prodType, scrip )
		}
		else if( entryOrderType == ORDER_TYPE_GUI_MARKET ){
			this.newEntryOrder.setOrderInput( entryOrderType, direction, qty, 0, 0, prodType, scrip  )
		}
		else if( entryOrderType == ORDER_TYPE_GUI_SL_MARKET ){
			this.newEntryOrder.setOrderInput( entryOrderType, direction, qty, 0, entryPrice, prodType, scrip  )
		}
		else if( entryOrderType == ORDER_TYPE_GUI_SL_LIMIT ){
			limitprice := direction == "B" ? entryPrice + MaxSlippage : entryPrice - MaxSlippage		
			this.newEntryOrder.setOrderInput( entryOrderType, direction, qty, limitprice, entryPrice, prodType, scrip )
		}
		else{			// should not happen
			MsgBox, 262144,, Entry Ordertype: %entryOrderType% is invalid
		}
	}
	
	/*	Set Stop Order Input details based on Order Type
	*/
	_setupStopOrderInput( stopOrderType, qty, prodType, stopPrice, direction, scrip ){
		global ORDER_TYPE_GUI_SL_MARKET, ORDER_TYPE_GUI_SL_LIMIT															// ORDER_TYPE_GUI_SL_LIMIT added on 13-6-16
		
		if( !IsObject( this.stopOrder ) )
			this.stopOrder := new OrderClass
				
		if( stopOrderType == ORDER_TYPE_GUI_SL_MARKET  || stopOrderType == ORDER_TYPE_GUI_SL_LIMIT){						// ORDER_TYPE_GUI_SL_LIMIT added on 13-6-16
			this.stopOrder.setOrderInput( stopOrderType, direction, qty, 0, stopPrice, prodType, scrip )
		}	
		else{			// should not happen
			MsgBox, 262144,, Stop Ordertype: %stopOrderType% is invalid
		}
	}
	
	/* Update Stop price - Set price / trigger price based on ordertype		
	*/
	_setStopPrice( price ){
		global ORDER_TYPE_GUI_SL_MARKET, ORDER_TYPE_GUI_SL_LIMIT                    										// ORDER_TYPE_GUI_SL_LIMIT added on 13-6-16
		
		stopOrderType := this.stopOrder.getInput().orderType
		
		if( stopOrderType == ORDER_TYPE_GUI_SL_MARKET || stopOrderType == ORDER_TYPE_GUI_SL_LIMIT){							// ORDER_TYPE_GUI_SL_LIMIT added on 13-6-16
			this.stopOrder.setInputPrice( 0, price )
		}	
		else{			// should not happen
			MsgBox, 262144,, Stop Ordertype: %stopOrderType% is invalid
		}
	}
		
	/*  Returns false if stop order should be created immediately
	*/
	_isStopPending( entryOrderType ){
		global
		return ( entryOrderType == ORDER_TYPE_GUI_SL_LIMIT || entryOrderType == ORDER_TYPE_GUI_SL_MARKET )
	}

	/*	If Open orders exist, Notify User. Used to warn before creating orders
	*/
	_checkOpenOrderEmpty(){
		global orderbookObj
		
		if( orderbookObj.doOpenOrdersExist() ){									// Entry
			MsgBox, % 262144+4,, Some Open Orders already exist . Continue?
			IfMsgBox No
				return false
		}
		return true
	}

	/* Go through orders in input csv
	   Check if trading symbol matches against Input
	   Setup OrderClass and push to input List	
	   Returns totalQty of Executed Orders if successful, else returns -1
	*/
	_loadExecutedOrders( isSilent, inputOrderCsv, outputOrderList, tradingSymbol  ){
		global orderbookObj

		totalQty := 0

		Loop, parse, inputOrderCsv, `,
		{
			orderID := A_LoopField
			if( orderID == "" )													// Extra Comma at the end
				break
			
			orderDetails := orderbookObj.getOrderDetails( orderID )

			if( !IsObject(orderDetails) ){
				UtilClass.conditionalMessage(isSilent, "Order " . orderID . " Not found"  )
				return -1
			}
			if( tradingSymbol != orderDetails.tradingSymbol ){
				UtilClass.conditionalMessage(isSilent, "Trading Symbol does not match for Order " . orderID  )
				return -1
			}

			order 			:= new OrderClass
			order.isCreated := true
			order.setOrderDetails( orderDetails )

			outputOrderList.Push( order )
			totalQty += orderDetails.totalQty
		}

		return totalQty
	}

	/* Returns latest order with highest order no from list of Executed Entry Orders
	*/
	_getLastExecutedInputOrder(){
		
		highestOrderNo := ""
		lastEntryOrder := -1
		
		For index, value in this.executedEntryOrderList{
			
			orderno := value.getOrderDetails().nowOrderNo		
			if( highestOrderNo == "" || highestOrderNo < orderno ){
				lastEntryOrder := value
				highestOrderNo := orderno
			}		
		}	

		return lastEntryOrder
	}

	/* Update Stop order
		1. Allow update of Stop order for open Entry Order, Stops can be pending
		2. Allow update of Stop order for executed Entry Order but no open Add order. Stops cannot be pending
		3. Allow update of Stop order for open Add Order + Executed Entry/Add orders. Stops can be pending
	*/
	_updateStop( inScrip, stopOrderType, qty, prodType, stopPrice ){
		
		if(  stopPrice == "" )
			return
		
		stopDirection	:= UtilClass.reverseDirection( this.direction )
	
		if( this.isNewEntryLinked() && !this.isEntryOrderExecuted()   ){			// 1. Update Stop Order for Open Entry Order. No Executed Enty/Add orders
																					// Stop size is only relevant if not pending, ie For Limit/Market orders
			this._setupStopOrderInput( stopOrderType, qty, prodType, stopPrice, stopDirection, inScrip )			
			if( !this.isStopPending )												// For Stop Entry Orders, Entry order size is used as stop size on Entry Trigger
				this.stopOrder.update()
		}
		else if( !this.isNewEntryLinked() && this.isEntryOrderExecuted()   ){		// 2. Update Stop Order for Executed Entry orders. No open Add order
			this._setupStopOrderInput( stopOrderType, this.positionSize, prodType, stopPrice, stopDirection, inScrip )
			this.stopOrder.update()
		}
		else if( this.isNewEntryLinked() && this.isEntryOrderExecuted()  ){			// 3. We have stops for both open and executed orders
		
			stopQty	:= this.positionSize + (this.isStopPending ? 0 : qty)			// If add order's stop is pending, Increasing stop size will be handled later on trigger, but update stop price if changed
																					// If No Pending order => Stop size = open + executed position				
			this._setupStopOrderInput( stopOrderType, stopQty, prodType, stopPrice, stopDirection, inScrip )
			this.stopOrder.update()
		}
		else{		// should not happen
			MsgBox, 262144,, Bug in _updateStop(). No stop order to update
		}
	}	
	
	/* Calculate Average Entry Price from executedEntryOrderList
	   Call this before updating this.positionSize
	*/
	_calculateAveragePrice(){
		For index, value in this.executedEntryOrderList{
			this.averageEntryPrice := this._getAveragePrice( this.positionSize, this.averageEntryPrice, value.getOrderDetails() )
		}	
	}
	
	/* Returns Updated Average weighted price - Call this before updating this.positionSize
	*/
	_getAveragePrice( oldQty, oldAverageprice, newOrderDetails ){
		_qty   	  := newOrderDetails.totalQty
		_avgPrice := newOrderDetails.averagePrice

		return ( oldAverageprice*oldQty + _avgPrice*_qty ) / (  oldQty + _qty )
	}

}
 

TracerBullet

Well-Known Member
I made some changes in Trade.ahk. It is working now. I remember 4 changes :lol: . I put remarks against them. TB, Please bear with me. Code is attached. Please see If I missed something.

Orderman is entering Price = 0 in SL order. This is treated as SL-M order by NOW. See below image.
Thats good. 0 is much better than adding slippage settings. Rest we will see in testing. Good to get familiar with part of code flow.

Do two more changes when free and then send merge to me.
1) Add Setting to choose between SLM and SL ordertype in OrderMan.ini, then read it in Settings.ahk and set STOP_ORDER_TYPE to ORDER_TYPE_GUI_SL_MARKET/ORDER_TYPE_GUI_SL_LIMIT.
2) Your Comments - no need to add date - just say setting 0 as Limit price to simulate SLM order.

Also, In git make sure you merge only changes that you did. I use "git gui" command to do the manual merge. github desktop seems to be inverse, need to select what not to merge. See partial commit here. So make sure only your changes are merged to commit and then send it to me. thanks

My only concern is that, after execution of entry is detected, Orderman enters Stop order immediately instead of waiting for the price to reach there. This may make it easier for big Auto traders to hunt stoploss.
Na, i doubt that. Never seen such thing yet. Anyway, Orderman has some lag too so should be ok. For normal day trading 3m /1m and up should be no problem. No idea about scalping. This is same as setting stop price in bracket orders ( except bracket orders will be faster as they dont have to automate GUI)