#include "sierrachart.h"

typedef std::vector<float> t_FloatVector;

void TradingSpreadOrderEntry_DrawStatusText(SCStudyInterfaceRef sc);
void TradingSpreadOrderEntry_UpdateTargetStopSubgraphs(SCStudyInterfaceRef sc, int BeginIndex, int EndIndex);


/*==========================================================================*/
SCSFExport scsf_TradingSpreadOrderEntry(SCStudyInterfaceRef sc)
{
	enum StudyStateEnum : int32_t
	{
		STATE_UNSET = 0
		, STATE_DISABLED = 1
		, STATE_MONITORING_FOR_SPREAD_PRICE_TRIGGER = 2
		, STATE_MONITORING_FOR_TARGET_AND_STOP = 3
		, STATE_DISABLED_AFTER_ORDERS_SENT = 4
		, STATE_DISABLED_INVALID_ENTRY_PRICE = 5
	};

	enum SpreadComparisonPriceOperatorEnum : int32_t
	{
		LESS_EQUAL = 0
		, GREATER_EQUAL = 1
	};

	SCSubgraphRef Subgraph_SpreadOrderPrice = sc.Subgraph[0];
	SCSubgraphRef Subgraph_OnChartTextDisplay = sc.Subgraph[1];
	SCSubgraphRef Subgraph_EntryPriceLine = sc.Subgraph[2];
	SCSubgraphRef Subgraph_TargetPriceLine = sc.Subgraph[3];
	SCSubgraphRef Subgraph_StopPriceLine = sc.Subgraph[4];

	SCInputRef Input_IsActiveAndWaitingForSpreadTriggerPrice = sc.Input[0];
	SCInputRef Input_Symbol1Symbol = sc.Input[1];
	SCInputRef Input_Symbol1Side = sc.Input[2];
	SCInputRef Input_Symbol1Quantity = sc.Input[3];

	SCInputRef Input_Symbol2Symbol = sc.Input[4];
	SCInputRef Input_Symbol2Side = sc.Input[5];
	SCInputRef Input_Symbol2Quantity = sc.Input[6];

	SCInputRef Input_Symbol3Symbol = sc.Input[7];
	SCInputRef Input_Symbol3Side = sc.Input[8];
	SCInputRef Input_Symbol3Quantity = sc.Input[9];

	SCInputRef Input_Symbol4Symbol = sc.Input[10];
	SCInputRef Input_Symbol4Side = sc.Input[11];
	SCInputRef Input_Symbol4Quantity = sc.Input[12];

	SCInputRef Input_SpreadEntryPrice = sc.Input[13];
	SCInputRef Input_SpreadEntryPriceOperator = sc.Input[14];

	SCInputRef Input_NumberOfBarsForSubgraphs = sc.Input[15];
	SCInputRef Input_DrawZeroValues = sc.Input[16];

	SCInputRef Input_UseTargetAfterFillOfSpreadEntry = sc.Input[17];
	SCInputRef Input_TargetSpreadPrice = sc.Input[18];

	SCInputRef Input_UseStopAfterFillOfSpreadEntry = sc.Input[19];
	SCInputRef Input_StopSpreadPrice = sc.Input[20];

	SCInputRef Input_DisableIfImmediateFillOfSpreadAfterSpreadPriceSet = sc.Input[21];
	SCInputRef Input_UseFullContractValuesForSpreadPrices = sc.Input[22];

	if (sc.SetDefaults)
	{
		sc.GraphName = "Trading: Spread Order Entry";
		sc.AutoLoop = 0;//Manual looping
		sc.GraphRegion = 1;
		sc.ScaleRangeType= SCALE_AUTO;
		sc.ValueFormat = VALUEFORMAT_INHERITED;
		sc.UpdateAlways = 1;
		sc.ReceivePointerEvents = ACS_RECEIVE_POINTER_EVENTS_ALWAYS;

		Subgraph_SpreadOrderPrice.Name = "Spread Price";
		Subgraph_SpreadOrderPrice.DrawStyle = DRAWSTYLE_LINE;
		Subgraph_SpreadOrderPrice.PrimaryColor = RGB(0,128,255);
		Subgraph_SpreadOrderPrice.LineLabel = LL_DISPLAY_VALUE | LL_VALUE_ALIGN_VALUES_SCALE| LL_VALUE_ALIGN_CENTER | LL_DISPLAY_NAME | LL_NAME_ALIGN_LEFT_EDGE | LL_NAME_ALIGN_CENTER;
		Subgraph_SpreadOrderPrice.DrawZeros = true;

		Subgraph_OnChartTextDisplay.Name = "Chart Text Display";
		Subgraph_OnChartTextDisplay.DrawStyle = DRAWSTYLE_CUSTOM_TEXT;
		Subgraph_OnChartTextDisplay.PrimaryColor = RGB(255, 165, 0);
		Subgraph_OnChartTextDisplay.LineWidth = 10;

		Subgraph_EntryPriceLine.Name = "Entry Price";
		Subgraph_EntryPriceLine.DrawStyle = DRAWSTYLE_LINE;
		Subgraph_EntryPriceLine.LineWidth = 2;
		Subgraph_EntryPriceLine.PrimaryColor = RGB(0, 255, 128);
		Subgraph_EntryPriceLine.LineLabel = LL_DISPLAY_VALUE | LL_VALUE_ALIGN_VALUES_SCALE | LL_VALUE_ALIGN_CENTER | LL_DISPLAY_NAME | LL_NAME_ALIGN_LEFT_EDGE | LL_NAME_ALIGN_CENTER;
		Subgraph_EntryPriceLine.DrawZeros = true;

		Subgraph_TargetPriceLine.Name = "Target Price";
		Subgraph_TargetPriceLine.DrawStyle = DRAWSTYLE_LINE;
		Subgraph_TargetPriceLine.LineWidth = 2;
		Subgraph_TargetPriceLine.PrimaryColor = RGB(255, 100, 0);
		Subgraph_TargetPriceLine.LineLabel = LL_DISPLAY_VALUE | LL_VALUE_ALIGN_VALUES_SCALE | LL_VALUE_ALIGN_CENTER | LL_DISPLAY_NAME | LL_NAME_ALIGN_LEFT_EDGE | LL_NAME_ALIGN_CENTER;
		Subgraph_TargetPriceLine.DrawZeros = true;

		Subgraph_StopPriceLine.Name = "Stop Price";
		Subgraph_StopPriceLine.DrawStyle = DRAWSTYLE_LINE;
		Subgraph_StopPriceLine.LineWidth = 2;
		Subgraph_StopPriceLine.PrimaryColor = RGB(255, 100, 0);
		Subgraph_StopPriceLine.LineLabel = LL_DISPLAY_VALUE | LL_VALUE_ALIGN_VALUES_SCALE | LL_VALUE_ALIGN_CENTER | LL_DISPLAY_NAME | LL_NAME_ALIGN_LEFT_EDGE | LL_NAME_ALIGN_CENTER;
		Subgraph_StopPriceLine.DrawZeros = true;

		Input_IsActiveAndWaitingForSpreadTriggerPrice.Name = "Is Active and Waiting for Spread Trigger Price";
		Input_IsActiveAndWaitingForSpreadTriggerPrice.SetYesNo(false);

		Input_Symbol1Symbol.Name = "Leg 1 Symbol";
		Input_Symbol1Symbol.SetSymbol("");

		Input_Symbol1Side.Name = "Leg 1 Side";
		Input_Symbol1Side.SetCustomInputStrings("Buy;Sell");
		Input_Symbol1Side.SetCustomInputIndex(0);

		Input_Symbol1Quantity.Name = "Leg 1 Quantity";
		Input_Symbol1Quantity.SetInt(1);

		Input_Symbol2Symbol.Name = "Leg 2 Symbol";
		Input_Symbol2Symbol.SetSymbol("");

		Input_Symbol2Side.Name = "Leg 2 Side";
		Input_Symbol2Side.SetCustomInputStrings("Buy;Sell");
		Input_Symbol2Side.SetCustomInputIndex(1);

		Input_Symbol2Quantity.Name = "Leg 2 Quantity";
		Input_Symbol2Quantity.SetInt(1);

		Input_Symbol3Symbol.Name = "Leg 3 Symbol";
		Input_Symbol3Symbol.SetSymbol("");

		Input_Symbol3Side.Name = "Leg 3 Side";
		Input_Symbol3Side.SetCustomInputStrings("Buy;Sell");
		Input_Symbol3Side.SetCustomInputIndex(0);

		Input_Symbol3Quantity.Name = "Leg 3 Quantity";
		Input_Symbol3Quantity.SetInt(0);

		Input_Symbol4Symbol.Name = "Leg 4 Symbol";
		Input_Symbol4Symbol.SetSymbol("");

		Input_Symbol4Side.Name = "Leg 4 Side";
		Input_Symbol4Side.SetCustomInputStrings("Buy;Sell");
		Input_Symbol4Side.SetCustomInputIndex(0);

		Input_Symbol4Quantity.Name = "Leg 4 Quantity";
		Input_Symbol4Quantity.SetInt(0);

		Input_SpreadEntryPrice.Name = "Spread Entry Price";
		Input_SpreadEntryPrice.SetFloat(0);

		Input_SpreadEntryPriceOperator.Name = "Spread Entry Price Operator";
		Input_SpreadEntryPriceOperator.SetCustomInputStrings("Less or Equal;Greater or Equal");
		Input_SpreadEntryPriceOperator.SetCustomInputIndex(LESS_EQUAL);

		Input_NumberOfBarsForSubgraphs.Name = "Number of Bars for Subgraphs";
		Input_NumberOfBarsForSubgraphs.SetInt(200);
		Input_NumberOfBarsForSubgraphs.SetIntLimits(1, 2000);

		Input_DrawZeroValues.Name = "Draw Zero Values";
		Input_DrawZeroValues.SetYesNo(false);

		Input_UseTargetAfterFillOfSpreadEntry.Name = "Use Target after Fill of Spread Entry";
		Input_UseTargetAfterFillOfSpreadEntry.SetYesNo(false);

		Input_TargetSpreadPrice.Name = "Target Spread Price";
		Input_TargetSpreadPrice.SetFloat(0);

		Input_UseStopAfterFillOfSpreadEntry.Name = "Use Stop after Fill of Spread Entry";
		Input_UseStopAfterFillOfSpreadEntry.SetYesNo(false);

		Input_StopSpreadPrice.Name = "Stop Spread Price";
		Input_StopSpreadPrice.SetFloat(0);

		Input_DisableIfImmediateFillOfSpreadAfterSpreadPriceSet.Name = "Disable if Immediate Fill of Spread After Spread Price Set";
		Input_DisableIfImmediateFillOfSpreadAfterSpreadPriceSet.SetYesNo(false);

		Input_UseFullContractValuesForSpreadPrices.Name = "Use Full Contract Values for Spread Prices";
		Input_UseFullContractValuesForSpreadPrices.SetYesNo(false);

		sc.AllowMultipleEntriesInSameDirection = 1;
		sc.AllowOppositeEntryWithOpposingPositionOrOrders = 1;
		sc.CancelAllOrdersOnEntriesAndReversals = 0;
		sc.AllowOnlyOneTradePerBar = 0;
		sc.SupportReversals = 0;
		sc.AllowEntryWithWorkingOrders = 1;
		sc.SupportAttachedOrdersForTrading = 0;
		sc.UseGUIAttachedOrderSetting = 0;
		sc.MaximumPositionAllowed = 100000000;


		return;
	}

	sc.DisplayAsMainPriceGraph = false;

	int& r_EnableSpreadOrderEntryMenuID = sc.GetPersistentInt(1);
	int& r_DisableSpreadOrderEntryMenuID = sc.GetPersistentInt(2);
	int& r_DisabledActiveStatus = sc.GetPersistentInt(3);
	int& r_CurrentState = sc.GetPersistentInt(4);
	int &r_DrawingNumber = sc.GetPersistentInt(5);
	int& r_OrderModifyMode = sc.GetPersistentInt(6);

	//will both be 0 upon opening the Chartbook or first-time study added
	double& r_PriorSpreadEntryPrice = sc.GetPersistentDouble(1);
	int& r_SpreadEntryPriceHasChanged = sc.GetPersistentInt(7);

	SCString& r_CurrentOnScreenMessage = sc.GetPersistentSCString(1);

	const int PersistentHistoricalSpreadDataKey = 1;
	t_FloatVector* p_PersistentHistoricalSpreadData = reinterpret_cast<t_FloatVector*>(sc.GetPersistentPointer(PersistentHistoricalSpreadDataKey));

	if (sc.LastCallToFunction)
	{
		// Be sure to remove the menu commands when study is removed
		sc.RemoveACSChartShortcutMenuItem(sc.ChartNumber, r_EnableSpreadOrderEntryMenuID);
		sc.RemoveACSChartShortcutMenuItem(sc.ChartNumber, r_DisableSpreadOrderEntryMenuID);

		if (p_PersistentHistoricalSpreadData != NULL)
		{
			delete p_PersistentHistoricalSpreadData;
			sc.SetPersistentPointer(PersistentHistoricalSpreadDataKey, NULL);
		}

		return;
	}

	if (p_PersistentHistoricalSpreadData == NULL)
	{
		p_PersistentHistoricalSpreadData = new t_FloatVector;

		if (p_PersistentHistoricalSpreadData != NULL)
			sc.SetPersistentPointer(PersistentHistoricalSpreadDataKey, p_PersistentHistoricalSpreadData);

	}

	if (p_PersistentHistoricalSpreadData == NULL)
		return;

	t_FloatVector& r_PersistentHistoricalSpreadData = *p_PersistentHistoricalSpreadData;
	r_PersistentHistoricalSpreadData.resize(Input_NumberOfBarsForSubgraphs.GetInt());


	// this will be true when study is added to chart, and when Chartbook is opened with study on chart. This is done as a safety.
	if (r_DisabledActiveStatus == 0)
	{
		Input_IsActiveAndWaitingForSpreadTriggerPrice.SetYesNo(false);
		r_CurrentState = STATE_DISABLED;
		r_DisabledActiveStatus = 1;
	}

	sc.SendOrdersToTradeService = sc.GlobalTradeSimulationIsOn ? 0 : 1;

	//sc.SendOrdersToTradeService = 0;// TEMPORARY: Safety during development and testing

	if (sc.IsFullRecalculation)
	{
		r_DrawingNumber = 0;

		if (Input_NumberOfBarsForSubgraphs.GetInt() == 0)
			Input_NumberOfBarsForSubgraphs.SetInt(100);

		Subgraph_SpreadOrderPrice.DrawZeros = Input_DrawZeroValues.GetBoolean();
		Subgraph_EntryPriceLine.DrawZeros = Input_DrawZeroValues.GetBoolean();

		if (Input_UseTargetAfterFillOfSpreadEntry.GetYesNo())
			Subgraph_TargetPriceLine.DrawZeros = Input_DrawZeroValues.GetBoolean();
		else
			Subgraph_TargetPriceLine.DrawZeros = false;

		if (Input_UseStopAfterFillOfSpreadEntry.GetYesNo())
			Subgraph_StopPriceLine.DrawZeros = Input_DrawZeroValues.GetBoolean();
		else
			Subgraph_StopPriceLine.DrawZeros = false;

		if (r_EnableSpreadOrderEntryMenuID <= 0)
		{
			r_EnableSpreadOrderEntryMenuID = sc.AddACSChartShortcutMenuItem(sc.ChartNumber, "Enable Spread Order Entry");
		}

		if (r_DisableSpreadOrderEntryMenuID <= 0)
		{
			r_DisableSpreadOrderEntryMenuID = sc.AddACSChartShortcutMenuItem(sc.ChartNumber, "Disable Spread Order Entry");
		}

		if (r_CurrentState == STATE_UNSET)
			r_CurrentState = STATE_DISABLED;

	}

	if (Input_IsActiveAndWaitingForSpreadTriggerPrice.GetYesNo())
	{
		sc.SetACSChartShortcutMenuItemEnabled(sc.ChartNumber, r_EnableSpreadOrderEntryMenuID, 0);
		sc.SetACSChartShortcutMenuItemEnabled(sc.ChartNumber, r_DisableSpreadOrderEntryMenuID, 1);
	}
	else
	{
		sc.SetACSChartShortcutMenuItemEnabled(sc.ChartNumber, r_EnableSpreadOrderEntryMenuID, 1);
		sc.SetACSChartShortcutMenuItemEnabled(sc.ChartNumber, r_DisableSpreadOrderEntryMenuID, 0);
	}

	if (!sc.ChartTradeModeEnabled)
	{
		r_CurrentOnScreenMessage = "Chart Trade Mode is not Enabled";
		TradingSpreadOrderEntry_DrawStatusText(sc);
		return;
	}

	// handle set trigger price menu clicks
	if (sc.MenuEventID != 0 && sc.MenuEventID == r_EnableSpreadOrderEntryMenuID)
	{
		Input_IsActiveAndWaitingForSpreadTriggerPrice.SetYesNo(true);

		if (r_CurrentState == STATE_DISABLED
			|| r_CurrentState == STATE_DISABLED_AFTER_ORDERS_SENT
			|| r_CurrentState == STATE_DISABLED_INVALID_ENTRY_PRICE)
		{
			r_CurrentState = STATE_MONITORING_FOR_SPREAD_PRICE_TRIGGER;
			r_CurrentOnScreenMessage = "Monitoring for spread entry price";
			TradingSpreadOrderEntry_DrawStatusText(sc);
		}

		sc.SetACSChartShortcutMenuItemEnabled(sc.ChartNumber, r_EnableSpreadOrderEntryMenuID, 0);
		sc.SetACSChartShortcutMenuItemEnabled(sc.ChartNumber, r_DisableSpreadOrderEntryMenuID, 1);

	
	}
	else if (sc.MenuEventID != 0 && sc.MenuEventID == r_DisableSpreadOrderEntryMenuID)
	{
		Input_IsActiveAndWaitingForSpreadTriggerPrice.SetYesNo(false);
		r_CurrentState = STATE_DISABLED;
		r_CurrentOnScreenMessage = "Disabled";
		TradingSpreadOrderEntry_DrawStatusText(sc);

		sc.SetACSChartShortcutMenuItemEnabled(sc.ChartNumber, r_EnableSpreadOrderEntryMenuID, 1);
		sc.SetACSChartShortcutMenuItemEnabled(sc.ChartNumber, r_DisableSpreadOrderEntryMenuID, 0);
	}
	
	const int NUM_SPREAD_ORDERS = 4;

	SCString SpreadSymbols[NUM_SPREAD_ORDERS];
	int32_t SpreadSides[NUM_SPREAD_ORDERS];
	uint32_t SpreadQuantities[NUM_SPREAD_ORDERS]; 

	SpreadSymbols[0] = Input_Symbol1Symbol.GetSymbol();
	SpreadSymbols[1] = Input_Symbol2Symbol.GetSymbol();
	SpreadSymbols[2] = Input_Symbol3Symbol.GetSymbol();
	SpreadSymbols[3] = Input_Symbol4Symbol.GetSymbol();

	SpreadSides[0] = Input_Symbol1Side.GetIndex();
	SpreadSides[1] = Input_Symbol2Side.GetIndex();
	SpreadSides[2] = Input_Symbol3Side.GetIndex();
	SpreadSides[3] = Input_Symbol4Side.GetIndex();
	
	SpreadQuantities[0] = Input_Symbol1Quantity.GetInt();
	SpreadQuantities[1] = Input_Symbol2Quantity.GetInt();
	SpreadQuantities[2] = Input_Symbol3Quantity.GetInt();
	SpreadQuantities[3] = Input_Symbol4Quantity.GetInt();


	if (SpreadSymbols[0].IsEmpty()	|| SpreadSymbols[1].IsEmpty()
		|| SpreadQuantities[0] == 0 || SpreadQuantities[1] == 0)
	{
		r_CurrentOnScreenMessage = "Settings not complete for spread entry";
		TradingSpreadOrderEntry_DrawStatusText(sc);
		return;
	}

	bool UseFullContractValues = Input_UseFullContractValuesForSpreadPrices.GetYesNo();

	double CurrentSpreadValue = 0.0;
	bool IsSpreadPriceValid = true;

	int NumberOfPricesInCalculation = 0;
	int NumberOfLegs = 0;
	int NumberOfBuys = 0;
	int NumberOfSells = 0;

	for (int SpreadOrderDataIndex = 0; SpreadOrderDataIndex < NUM_SPREAD_ORDERS; ++SpreadOrderDataIndex	)
	{

		if (SpreadQuantities[SpreadOrderDataIndex] == 0.0)
			continue;

		if (SpreadSymbols[SpreadOrderDataIndex].IsEmpty())
			continue;

		++NumberOfLegs;

		s_SCBasicSymbolData BasicSymbolData;
		sc.GetBasicSymbolData(SpreadSymbols[SpreadOrderDataIndex].GetChars(), BasicSymbolData, true);


		if (BasicSymbolData.Bid == 0.0f && BasicSymbolData.Ask == 0.0f)
		{
			r_CurrentOnScreenMessage = "Bid and Ask prices are zero";
			TradingSpreadOrderEntry_DrawStatusText(sc);
			IsSpreadPriceValid = false;
		}

		if (SpreadSides[SpreadOrderDataIndex] == 0)//Buy
		{
			const float AskPrice = BasicSymbolData.Ask * BasicSymbolData.DisplayPriceMultiplier;

			if (UseFullContractValues)
			{
				CurrentSpreadValue += (AskPrice / BasicSymbolData.TickSize * max(BasicSymbolData.CurrencyValuePerTick, BasicSymbolData.TickSize)) * SpreadQuantities[SpreadOrderDataIndex];
			}
			else
				CurrentSpreadValue += AskPrice * SpreadQuantities[SpreadOrderDataIndex];

			++NumberOfPricesInCalculation;
			NumberOfBuys++;
		}
		else if (SpreadSides[SpreadOrderDataIndex] == 1)//Sell
		{
			const float BidPrice = BasicSymbolData.Bid * BasicSymbolData.DisplayPriceMultiplier;

			if (UseFullContractValues)
			{
				CurrentSpreadValue -= (BidPrice / BasicSymbolData.TickSize * max(BasicSymbolData.CurrencyValuePerTick, BasicSymbolData.TickSize)) * SpreadQuantities[SpreadOrderDataIndex];
			}
			else
				CurrentSpreadValue -= BidPrice * SpreadQuantities[SpreadOrderDataIndex];

			++NumberOfPricesInCalculation;
			NumberOfSells++;
		}
	}



	double RegionHigh = 0.0;
	double RegionLow = 0.0;

	sc.GetGraphVisibleHighAndLow(RegionHigh, RegionLow);

	bool AllowModify = !((RegionHigh == 0.0 && RegionLow == 0.0)
		|| sc.ActiveToolYValue > RegionHigh
		|| sc.ActiveToolYValue < RegionLow);

	if (!AllowModify)
		r_OrderModifyMode = 0;

	if (AllowModify && Input_UseTargetAfterFillOfSpreadEntry.GetYesNo()
		&& r_OrderModifyMode != 2 && r_OrderModifyMode != 3)//Not modifying Stop or Entry
	{
		double TargetPrice = Input_TargetSpreadPrice.GetDouble();
		int YPosition = sc.RegionValueToYPixelCoordinate(static_cast<float>(TargetPrice), sc.GraphRegion);

		if (sc.PointerEventType == SC_POINTER_BUTTON_DOWN)
		{
			if(YPosition >= sc.PointerVertWindowCoord - 5
				&& YPosition <= sc.PointerVertWindowCoord + 5)
				r_OrderModifyMode = 1;
		}
			
		if (sc.PointerEventType == SC_POINTER_BUTTON_UP)
			r_OrderModifyMode = 0;

		if (r_OrderModifyMode == 1 && sc.PointerEventType == SC_POINTER_MOVE)
		{
			Input_TargetSpreadPrice.SetFloat((float)sc.RoundToTickSize(sc.ActiveToolYValue ));
		}
	}

	if (AllowModify && Input_UseStopAfterFillOfSpreadEntry.GetYesNo()
		&& r_OrderModifyMode != 1 && r_OrderModifyMode != 3)
	{
		double StopPrice = Input_StopSpreadPrice.GetDouble();
		int Yposition = sc.RegionValueToYPixelCoordinate(static_cast<float>(StopPrice), sc.GraphRegion);

		if (sc.PointerEventType == SC_POINTER_BUTTON_DOWN)
		{
			if (Yposition >= sc.PointerVertWindowCoord - 5
				&& Yposition <= sc.PointerVertWindowCoord + 5)
				r_OrderModifyMode = 2;
		}

		if (sc.PointerEventType == SC_POINTER_BUTTON_UP)
			r_OrderModifyMode = 0;

		if (r_OrderModifyMode == 2 && sc.PointerEventType == SC_POINTER_MOVE)
		{
			Input_StopSpreadPrice.SetFloat((float)sc.RoundToTickSize(sc.ActiveToolYValue));
		}
	}

	if (AllowModify && r_OrderModifyMode != 1 && r_OrderModifyMode != 2)
	{
		double EntryPrice = Input_SpreadEntryPrice.GetDouble();
		int YPosition = sc.RegionValueToYPixelCoordinate(static_cast<float>(EntryPrice), sc.GraphRegion);

		if (sc.PointerEventType == SC_POINTER_BUTTON_DOWN)
		{
			if (YPosition >= sc.PointerVertWindowCoord - 5
				&& YPosition <= sc.PointerVertWindowCoord + 5)
				r_OrderModifyMode = 3;
		}

		if (sc.PointerEventType == SC_POINTER_BUTTON_UP)
			r_OrderModifyMode = 0;

		if (r_OrderModifyMode == 3 && sc.PointerEventType == SC_POINTER_MOVE)
		{
			Input_SpreadEntryPrice.SetFloat((float)sc.RoundToTickSize(sc.ActiveToolYValue));
		}
	}

	//Check here for changes with spread order entry price
	if (r_PriorSpreadEntryPrice != Input_SpreadEntryPrice.GetFloat())
		r_SpreadEntryPriceHasChanged = 1;

	r_PriorSpreadEntryPrice = Input_SpreadEntryPrice.GetFloat();

	int BarStartIndex = sc.UpdateStartIndex;
	int EarliestIndex = sc.ArraySize - Input_NumberOfBarsForSubgraphs.GetInt();
	if (EarliestIndex > BarStartIndex)
	{
		BarStartIndex = EarliestIndex;
	}

	if (r_OrderModifyMode != 0 && BarStartIndex > EarliestIndex)
		BarStartIndex = EarliestIndex;

	// zero values before the bar starting index for the values
	for (int BarIndex = sc.UpdateStartIndex; BarIndex < BarStartIndex; BarIndex++)
	{
		Subgraph_EntryPriceLine[BarIndex] = 0;
		Subgraph_TargetPriceLine[BarIndex] = 0;
		Subgraph_StopPriceLine[BarIndex] = 0;
		Subgraph_SpreadOrderPrice[BarIndex] = 0;
	}

	for (int BarIndex = BarStartIndex; BarIndex < sc.ArraySize; BarIndex++)
	{
		Subgraph_EntryPriceLine[BarIndex] = Input_SpreadEntryPrice.GetFloat();

		if (Input_UseTargetAfterFillOfSpreadEntry.GetYesNo())
			Subgraph_TargetPriceLine[BarIndex] = Input_TargetSpreadPrice.GetFloat();

		if (Input_UseStopAfterFillOfSpreadEntry.GetYesNo())
			Subgraph_StopPriceLine[BarIndex] = Input_StopSpreadPrice.GetFloat();

	}

	if (sc.IsFullRecalculation )
	{
		const int VectorSize = static_cast<int>(r_PersistentHistoricalSpreadData.size());

		int OutputIndex = sc.ArraySize - VectorSize;

		for (int Index = 0; Index < VectorSize; ++Index)
		{
			Subgraph_SpreadOrderPrice[OutputIndex] = r_PersistentHistoricalSpreadData[Index];
			++OutputIndex;
		}		
	}
	else if(IsSpreadPriceValid
		&& Subgraph_SpreadOrderPrice[sc.ArraySize - 1] != (float)CurrentSpreadValue)
	{
		//shift the current spread price values back
		for (int BarIndex = EarliestIndex; BarIndex < sc.ArraySize - 1; BarIndex++)
		{
			Subgraph_SpreadOrderPrice[BarIndex] = Subgraph_SpreadOrderPrice[BarIndex + 1];
		}

		const int VectorSize = static_cast<int>(r_PersistentHistoricalSpreadData.size());
		for (int Index = 0; Index < VectorSize-1; ++Index)
		{
			r_PersistentHistoricalSpreadData[Index] = r_PersistentHistoricalSpreadData[Index + 1];
		}
				
	}

	if (IsSpreadPriceValid)
	{
		Subgraph_SpreadOrderPrice[sc.ArraySize - 1] = (float)CurrentSpreadValue;

		if (!r_PersistentHistoricalSpreadData.empty())
			r_PersistentHistoricalSpreadData.back() = (float)CurrentSpreadValue;
	}

	for (int BarIndex = EarliestIndex - 1; BarIndex >= 0; --BarIndex)
	{
		if (Subgraph_SpreadOrderPrice[BarIndex] == 0
			&& Subgraph_EntryPriceLine[BarIndex] == 0
			&& Subgraph_TargetPriceLine[BarIndex] == 0
			&& Subgraph_StopPriceLine[BarIndex] == 0)
			break;

		Subgraph_SpreadOrderPrice[BarIndex] = 0;
		Subgraph_EntryPriceLine[BarIndex] = 0;
		Subgraph_TargetPriceLine[BarIndex] = 0;
		Subgraph_StopPriceLine[BarIndex] = 0;
	}

	if (sc.IsFullRecalculation)//Do not do any spread price evaluation on a full recalculation
	{
		if (r_CurrentState == STATE_MONITORING_FOR_SPREAD_PRICE_TRIGGER
			|| r_CurrentState == STATE_MONITORING_FOR_TARGET_AND_STOP)
		{
			r_CurrentOnScreenMessage = "Waiting to begin monitoring";
			TradingSpreadOrderEntry_DrawStatusText(sc);
		}

		return;
	}

	if (NumberOfPricesInCalculation != NumberOfLegs)
	{
		r_CurrentOnScreenMessage = "Number of prices in calculation != to the number of legs";
		TradingSpreadOrderEntry_DrawStatusText(sc);
		return;
	}

	if (NumberOfLegs == 2 && NumberOfBuys != NumberOfSells)
	{
		r_CurrentOnScreenMessage = "Disabled: Number of buys != number of sells for 2 legs";
		Input_IsActiveAndWaitingForSpreadTriggerPrice.SetYesNo(false);
		r_CurrentState = STATE_DISABLED;
		TradingSpreadOrderEntry_DrawStatusText(sc);
		return;
	}


	bool UseTargetOrStop = Input_UseTargetAfterFillOfSpreadEntry.GetYesNo() || Input_UseStopAfterFillOfSpreadEntry.GetYesNo();


	if (!Input_IsActiveAndWaitingForSpreadTriggerPrice.GetYesNo()
		|| (r_CurrentState == STATE_MONITORING_FOR_TARGET_AND_STOP  && !UseTargetOrStop))
	{
		
		if (r_CurrentState != STATE_DISABLED
			&& r_CurrentState != STATE_DISABLED_AFTER_ORDERS_SENT
			&& r_CurrentState != STATE_DISABLED_INVALID_ENTRY_PRICE)
			r_CurrentState = STATE_DISABLED;

		if(r_CurrentState != STATE_DISABLED_AFTER_ORDERS_SENT
			&& r_CurrentState != STATE_DISABLED_INVALID_ENTRY_PRICE)
			r_CurrentOnScreenMessage = "Disabled";

		TradingSpreadOrderEntry_DrawStatusText(sc);
		return;
	}

	if(r_CurrentState == STATE_DISABLED 
		|| r_CurrentState == STATE_DISABLED_AFTER_ORDERS_SENT
		|| r_CurrentState == STATE_DISABLED_INVALID_ENTRY_PRICE)
	{
		r_CurrentState = STATE_MONITORING_FOR_SPREAD_PRICE_TRIGGER;

	}

	if (r_CurrentState == STATE_MONITORING_FOR_SPREAD_PRICE_TRIGGER)
	{

		r_CurrentOnScreenMessage = "Monitoring for spread entry price";
		TradingSpreadOrderEntry_DrawStatusText(sc);
	}

	if (r_OrderModifyMode != 0)
		return;


	if (!IsSpreadPriceValid)
		return;


	int NumberOfPricesToCompare = 0;
	double SpreadPricesToCompareTo[2] = { 0 };
	SpreadComparisonPriceOperatorEnum ComparisonOperators[2] = {LESS_EQUAL};
	if (r_CurrentState == STATE_MONITORING_FOR_SPREAD_PRICE_TRIGGER)
	{
		SpreadPricesToCompareTo[0]= Input_SpreadEntryPrice.GetFloat();
		NumberOfPricesToCompare = 1;
		ComparisonOperators[0] 
			= (SpreadComparisonPriceOperatorEnum)Input_SpreadEntryPriceOperator.GetIndex();
	}
	else if (r_CurrentState == STATE_MONITORING_FOR_TARGET_AND_STOP)
	{
		// In the case of greater or equal, invert the operator for the exit order that is lower than the entry.

		// In the case of less or equal, invert the operator for the exit order that is higher than the entry.
		if (Input_UseTargetAfterFillOfSpreadEntry.GetYesNo())
		{
			SpreadPricesToCompareTo[NumberOfPricesToCompare] = Input_TargetSpreadPrice.GetFloat();

			if (Input_SpreadEntryPriceOperator.GetIndex() == LESS_EQUAL
				&& SpreadPricesToCompareTo[NumberOfPricesToCompare] > Input_SpreadEntryPrice.GetFloat())
			{
				ComparisonOperators[NumberOfPricesToCompare] = GREATER_EQUAL;
			}
			else if (Input_SpreadEntryPriceOperator.GetIndex() == GREATER_EQUAL
				&& SpreadPricesToCompareTo[NumberOfPricesToCompare] < Input_SpreadEntryPrice.GetFloat())
			{
				ComparisonOperators[NumberOfPricesToCompare] = LESS_EQUAL;
			}
			else
			{
				ComparisonOperators[NumberOfPricesToCompare]
					= (SpreadComparisonPriceOperatorEnum)Input_SpreadEntryPriceOperator.GetIndex();
			}

			NumberOfPricesToCompare++;
		}

		if (Input_UseStopAfterFillOfSpreadEntry.GetYesNo())
		{
			SpreadPricesToCompareTo[NumberOfPricesToCompare] = Input_StopSpreadPrice.GetFloat();

			if (Input_SpreadEntryPriceOperator.GetIndex() == LESS_EQUAL
				&& SpreadPricesToCompareTo[NumberOfPricesToCompare] > Input_SpreadEntryPrice.GetFloat())
			{
				ComparisonOperators[NumberOfPricesToCompare] = GREATER_EQUAL;
			}
			else if (Input_SpreadEntryPriceOperator.GetIndex() == GREATER_EQUAL
				&& SpreadPricesToCompareTo[NumberOfPricesToCompare] < Input_SpreadEntryPrice.GetFloat())
			{
				ComparisonOperators[NumberOfPricesToCompare] = LESS_EQUAL;
			}
			else
			{
				ComparisonOperators[NumberOfPricesToCompare]
					= (SpreadComparisonPriceOperatorEnum)Input_SpreadEntryPriceOperator.GetIndex();
			}

			NumberOfPricesToCompare++;
		}

	}

	bool SpreadPriceMet = false;

	for(int Index = 0; Index  < NumberOfPricesToCompare; Index++)
	{
		if (ComparisonOperators[Index] == LESS_EQUAL)
		{
			if (CurrentSpreadValue <= SpreadPricesToCompareTo[Index])
			{
				if (r_CurrentState == STATE_MONITORING_FOR_SPREAD_PRICE_TRIGGER)
					r_CurrentOnScreenMessage = "Triggered - ";
				else
					r_CurrentOnScreenMessage = "Target/Stop Triggered - ";

				SpreadPriceMet = true;
			}

		}
		else if (ComparisonOperators[Index] == GREATER_EQUAL)
		{
			if (CurrentSpreadValue >= SpreadPricesToCompareTo[Index])
			{
				if (r_CurrentState == STATE_MONITORING_FOR_SPREAD_PRICE_TRIGGER)
					r_CurrentOnScreenMessage = "Triggered - ";
				else
					r_CurrentOnScreenMessage = "Target/Stop Triggered - ";

				SpreadPriceMet = true;
			}

		}
		else
			return;

	}

	if (SpreadPriceMet)
	{
		if (r_SpreadEntryPriceHasChanged
			&& Input_DisableIfImmediateFillOfSpreadAfterSpreadPriceSet.GetYesNo())
		{
			r_SpreadEntryPriceHasChanged = 0;

			Input_IsActiveAndWaitingForSpreadTriggerPrice.SetYesNo(false);
			r_CurrentState = STATE_DISABLED_INVALID_ENTRY_PRICE;
			r_CurrentOnScreenMessage = "Disabled: DisableIfImmediateFillOfSpreadAfterSpreadPriceSet";

			TradingSpreadOrderEntry_DrawStatusText(sc);
			return;
		}

		r_SpreadEntryPriceHasChanged = 0;
	}
	else
	{
		return;
	}
	

	if (!Input_IsActiveAndWaitingForSpreadTriggerPrice.GetYesNo())
		return;//this will not be reached but is here for safety.

	if (r_CurrentState != STATE_MONITORING_FOR_SPREAD_PRICE_TRIGGER
		&& r_CurrentState != STATE_MONITORING_FOR_TARGET_AND_STOP)
		return;


	//From this point on *must* get to end of function for safety so state will be set to disabled or monitoring for target or stop.


	r_CurrentOnScreenMessage += sc.FormatDateTime(sc.CurrentSystemDateTime);
	r_CurrentOnScreenMessage += ". ";

	bool Successful = false;
	for (int SpreadOrderDataIndex = 0; SpreadOrderDataIndex < NUM_SPREAD_ORDERS; ++SpreadOrderDataIndex)
	{

		if (SpreadQuantities[SpreadOrderDataIndex] == 0.0)
			continue;

		if (SpreadSymbols[SpreadOrderDataIndex].IsEmpty())
			continue;

		
		if (SpreadOrderDataIndex > 0)
			r_CurrentOnScreenMessage += ", ";
	
		// At this point it is safe to submit the market order

		s_SCNewOrder NewOrder;
		NewOrder.OrderQuantity = SpreadQuantities[SpreadOrderDataIndex];
		NewOrder.OrderType = SCT_ORDERTYPE_MARKET;
		NewOrder.TimeInForce = SCT_TIF_DAY;

		NewOrder.Symbol = SpreadSymbols[SpreadOrderDataIndex];
		NewOrder.TradeAccount = sc.SelectedTradeAccount;
		NewOrder.TextTag = "Spread order entry leg";

		int Result = 0;
		if (r_CurrentState == STATE_MONITORING_FOR_TARGET_AND_STOP  && UseTargetOrStop)
		{
			if (SpreadSides[SpreadOrderDataIndex] == 0)//Buy
				Result = static_cast<int>(sc.SellOrder(NewOrder));
			else if (SpreadSides[SpreadOrderDataIndex] == 1)//Sell
				Result = static_cast<int>(sc.BuyOrder(NewOrder));
		}
		else
		{
			if (SpreadSides[SpreadOrderDataIndex] == 0)//Buy
				Result = static_cast<int>(sc.BuyOrder(NewOrder));
			else if (SpreadSides[SpreadOrderDataIndex] == 1)//Sell
				Result = static_cast<int>(sc.SellOrder(NewOrder));
		}

		if (Result < 0)
		{
			r_CurrentOnScreenMessage = "Submission error: ";
			r_CurrentOnScreenMessage  += sc.GetTradingErrorTextMessage(Result);
		}
		else
		{
			Successful = true;
			r_CurrentOnScreenMessage += NewOrder.Symbol;
			r_CurrentOnScreenMessage += "*";
			if (r_CurrentState == STATE_MONITORING_FOR_TARGET_AND_STOP  && UseTargetOrStop)
			{
				if (SpreadSides[SpreadOrderDataIndex] == 0)
					r_CurrentOnScreenMessage += "-";
			}
			else 
			{
				if (SpreadSides[SpreadOrderDataIndex] == 1)
					r_CurrentOnScreenMessage += "-";
			}

			r_CurrentOnScreenMessage.AppendFormat("%d", NewOrder.OrderQuantity);

			SCString MessageText("Market order submitted for spread leg ");
			MessageText += NewOrder.Symbol;
			sc.AddMessageToTradeServiceLog(MessageText, false);

		}

	}

	//Disable or monitor for target or stop

	if (!UseTargetOrStop)
	{
		Input_IsActiveAndWaitingForSpreadTriggerPrice.SetYesNo(false);//Disable
		r_CurrentOnScreenMessage += ". Not Monitoring";
		r_CurrentState = STATE_DISABLED_AFTER_ORDERS_SENT;

		Input_IsActiveAndWaitingForSpreadTriggerPrice.SetYesNo(false);//Disable
	}
	else
	{
		if(r_CurrentState == STATE_MONITORING_FOR_SPREAD_PRICE_TRIGGER)
		{
			r_CurrentOnScreenMessage += ". Monitoring Target/Stop";
			r_CurrentState = STATE_MONITORING_FOR_TARGET_AND_STOP;
		}
		else
		{
			r_CurrentOnScreenMessage += ". Not Monitoring";
			r_CurrentState = STATE_DISABLED_AFTER_ORDERS_SENT;
			Input_IsActiveAndWaitingForSpreadTriggerPrice.SetYesNo(false);//Disable
		}

	}


	TradingSpreadOrderEntry_DrawStatusText(sc);
} 

/*==========================================================================*/
void TradingSpreadOrderEntry_DrawStatusText(SCStudyInterfaceRef sc )
{

	SCSubgraphRef Subgraph_OnChartTextDisplay = sc.Subgraph[1];

	int &r_DrawingNumber = sc.GetPersistentInt(5);
	
	SCString& r_CurrentOnScreenMessage = sc.GetPersistentSCString(1);

	s_UseTool Tool;

	Tool.Clear();
	Tool.ChartNumber = sc.ChartNumber;
	Tool.DrawingType = DRAWING_TEXT;
	Tool.BeginDateTime = 10;
	Tool.Region = sc.GraphRegion;
	Tool.BeginValue = 90;
	Tool.UseRelativeVerticalValues = true;
	Tool.Color = Subgraph_OnChartTextDisplay.PrimaryColor;
	Tool.FontBold = true;

	Tool.Text = r_CurrentOnScreenMessage;
	Tool.FontSize = Subgraph_OnChartTextDisplay.LineWidth;
	Tool.AddMethod = UTAM_ADD_OR_ADJUST;
	Tool.ReverseTextColor = false;

	if (r_DrawingNumber != 0)
		Tool.LineNumber = r_DrawingNumber;

	if(sc.UseTool(Tool))
		r_DrawingNumber = Tool.LineNumber;

}

/*==========================================================================*/
void TradingSpreadOrderEntry_UpdateTargetStopSubgraphs(SCStudyInterfaceRef sc, int BeginIndex, int EndIndex)
{

	SCSubgraphRef Subgraph_TargetPriceLine = sc.Subgraph[3];
	SCSubgraphRef Subgraph_StopPriceLine = sc.Subgraph[4];

	SCInputRef Input_UseTargetAfterFillOfSpreadEntry = sc.Input[17];
	SCInputRef Input_TargetSpreadPrice = sc.Input[18];

	SCInputRef Input_UseStopAfterFillOfSpreadEntry = sc.Input[19];
	SCInputRef Input_StopSpreadPrice = sc.Input[20];

	for (int BarIndex = BeginIndex; BarIndex < EndIndex; BarIndex++)
	{
	
		if (Input_UseTargetAfterFillOfSpreadEntry.GetYesNo())
			Subgraph_TargetPriceLine[BarIndex] = Input_TargetSpreadPrice.GetFloat();

		if (Input_UseStopAfterFillOfSpreadEntry.GetYesNo())
			Subgraph_StopPriceLine[BarIndex] = Input_StopSpreadPrice.GetFloat();

	}
}