
//
// Copyright (C) 2019, Order Flow Analytics Inc <www.orderflowanalytics.com>.
// OFA reserves the right to modify or overwrite this NinjaScript component with each release.
//
// By installing, using in whole or in part any sample code from Order Flow Analytics you agree to fully indemnify and hold harmless OrderFlowAnalytics, Inc 
// and its affiliates from and against any claims, losses, liabilities and expenses that may be incurred 
// as a result having downloaded and/or used any or all of the available code.
// Do thoroughly test any code & modifications for indicators and strategies in Replay Test mode


#region Using declarations
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Input;
using System.Windows.Media;
using System.Xml.Serialization;
using NinjaTrader.Cbi;
using NinjaTrader.Gui;
using NinjaTrader.Gui.Chart;
using NinjaTrader.Gui.SuperDom;
using NinjaTrader.Gui.Tools;
using NinjaTrader.Data;
using NinjaTrader.NinjaScript;
using NinjaTrader.Core.FloatingPoint;
using NinjaTrader.NinjaScript.Indicators;
using NinjaTrader.NinjaScript.DrawingTools;
//using NinjaTrader.OFA;
#endregion

//This namespace holds Strategies in this folder and is required. Do not change it. 
namespace NinjaTrader.NinjaScript.Strategies
{
	public class OFASampleStrategyCWAPVWAPRunOnce : Strategy
	{
		private OFAIndSTProfileAccess OFAIndicatorSTProfile1;
		
		private double EntryPrice = 0.0, StopPrice = 0.0;
		private bool breakevenset=false;
		private bool positionOpened=false;

		protected override void OnStateChange()
		{
			if (State == State.SetDefaults)
			{
				Description									= @"Enter the description for your new custom Strategy here.";
				Name										= "OFASampleStrategyCWAPVWAPRunOnce";
				Calculate									= Calculate.OnEachTick;
				EntriesPerDirection							= 1;
				EntryHandling								= EntryHandling.AllEntries;
				IsExitOnSessionCloseStrategy				= true;
				ExitOnSessionCloseSeconds					= 30;
				IsFillLimitOnTouch							= false;
				MaximumBarsLookBack							= MaximumBarsLookBack.TwoHundredFiftySix;
				OrderFillResolution							= OrderFillResolution.Standard;
				Slippage									= 0;
				StartBehavior								= StartBehavior.WaitUntilFlat;
				TimeInForce									= TimeInForce.Gtc;
				TraceOrders									= false;
				RealtimeErrorHandling						= RealtimeErrorHandling.StopCancelClose;
				StopTargetHandling							= StopTargetHandling.PerEntryExecution;
				BarsRequiredToTrade							= 20;
				StopLossTicks				   = 10;
				ProfitTargetTicks			   = 20;
				StopBreakEvenTicks			   = 8;
				RiskToleranceTicks 			   = 12;
				EntryOffset					   = 1;  
				StopOffset					   = 1;
				RunOnce					   = true;
				
				// Disable this property for performance gains in Strategy Analyzer optimizations
				// See the Help Guide for additional information
				IsInstantiatedOnEachOptimizationIteration	= true;
			}
			else if (State == State.Configure)
			{
				// Use here only if your stop loss price/offset is static
				// otherwise use in onbarupdate - to enable dynamically changing the stop loss price while in an open position
				// if using this in onbarupdate - make sure you reset the stop loss price/offset when the strategy is flat - important or the last price/offset will be used to generate
				// the stop loss order on your next open position
				
				
				SetStopLoss(CalculationMode.Ticks,StopLossTicks);
				SetProfitTarget(CalculationMode.Ticks,ProfitTargetTicks);
			}
			else if (State == State.DataLoaded)
			{				
				OFAIndicatorSTProfile1			= OFAIndSTProfileAccess(Close);
			}
		}

		protected override void OnBarUpdate()
		{
			
			// For strategies accessing the Active Profile Elements return if in Historical state
			
			if (State == State.Historical)
				return;
			
			if (BarsInProgress != 0) 
				return;

			// Ensure you have enough bars on the chart if you are referencing prior bars in your logic below !
			
			if (CurrentBars[0] < 5)
				return;
			
			// Resets the stop loss to the original value when all positions are closed
			// this ensures any prior active profile variable used which may be no longer relevant to next trade is cleared and a default is used.
			
			if (Position.MarketPosition == MarketPosition.Flat)
			{
				SetStopLoss(CalculationMode.Ticks, StopLossTicks);
				breakevenset=false;
				
				if (RunOnce)
				{
					if (positionOpened)
						CloseStrategy("My Cwap Vwap Strategy Close");
				}
			}
			
			// If a long position is open, allow for stop loss modification to breakeven
			else if (Position.MarketPosition == MarketPosition.Long)
			{
				// Once the price is greater than entry price+StopBreakEvenTicks set as a parameter, set stop loss to breakeven
				// If break even is not set then set. If it has been set then leave open for user to move the stop with chart trader without it being automatically
				// reset back
				
				// Keep track that a long position was opened for the RunOnce option
				
				positionOpened = true;
				
				if ((Close[0] > Position.AveragePrice + StopBreakEvenTicks * TickSize) && (!breakevenset))
				{
					SetStopLoss(CalculationMode.Price, Position.AveragePrice);
					breakevenset = true;
				}
				else
				{
					// Update Stop price to the dynamic active profile element chosen as a stop
				
					if (breakevenset)
					{
						// check first we are not setting the stop to an adverse/worse price than breakeven
						
						if (OFAIndicatorSTProfile1.OFAActiveProfileVwap > Position.AveragePrice)
							SetStopLoss(CalculationMode.Price, OFAIndicatorSTProfile1.OFAActiveProfileVwap - (StopOffset)*TickSize);
					}
					else
						SetStopLoss(CalculationMode.Price, OFAIndicatorSTProfile1.OFAActiveProfileVwap - (StopOffset)*TickSize);
				}		
			}
			else if (Position.MarketPosition == MarketPosition.Short)
			{
				// Once the price is greater than entry price-StopBreakEvenTicks set as a parameter, set stop loss to breakeven
				// If break even is not set then set. If it has been set then leave open for user to move the stop with chart trader without it being automatically
				// reset back
				
				// Keep track that a short position was opened for the RunOnce option
				
				positionOpened = true;
				
				if ((Close[0] < Position.AveragePrice - StopBreakEvenTicks * TickSize) && (!breakevenset))
				{
					SetStopLoss(CalculationMode.Price, Position.AveragePrice);
					breakevenset = true;
				}
				else 
				{
					// Update Stop price to the dynamic active profile element chosen as a stop
					
					if (breakevenset)
					{
						// check first we are not setting the stop to an adverse/worse price than breakeven
						
						if (OFAIndicatorSTProfile1.OFAActiveProfileVwap < Position.AveragePrice)
							SetStopLoss(CalculationMode.Price, OFAIndicatorSTProfile1.OFAActiveProfileVwap + (StopOffset)*TickSize);
					}
					else
						SetStopLoss(CalculationMode.Price, OFAIndicatorSTProfile1.OFAActiveProfileVwap + (StopOffset)*TickSize);
					
				}		
			}
			
			
			// Check Active Profile Exists/Enabled and is ready on the OFA chart
			// Must always check this first before accessing profile details
			
			// Only enter this section if not in Historical State
			

			if (OFAIndicatorSTProfile1.OFAIsActiveProfileEnabled)
			{
				// Logic flow - make sure the direction makes sense in context with your chosen entry and stop variable being used
				//
				// If plan to go long ensure the entry price is > stop 
				
				// Check if Risk is within tolerance for cwap vwap trade using the cwapvwaprisk
				
//				Print("active profile enabled risk = ");
//				Print(OFAIndicatorSTProfile1.OFAActiveProfileCWAPVWAPRisk);
				
				// You may want to take into account any offsets used for Entry and Stop in the overall risk tolerance
				// in addition to the parameter value provided
				
				if (OFAIndicatorSTProfile1.OFAActiveProfileCWAPVWAPRisk <= RiskToleranceTicks)
				{
					
					if (OFAIndicatorSTProfile1.OFAActiveProfileCwap < Instrument.MasterInstrument.RoundToTickSize(GetCurrentAsk()))
					{
						
						// Now check where our planned stop is - is the Vwap < Cwap
						
						if (OFAIndicatorSTProfile1.OFAActiveProfileVwap < OFAIndicatorSTProfile1.OFAActiveProfileCwap )
						{
						
							// Enter Long Limit with an offset of 1 tick
						
							EnterLongLimit(OFAIndicatorSTProfile1.OFAActiveProfileCwap + (EntryOffset)*TickSize);
						}
					}	
					else if (OFAIndicatorSTProfile1.OFAActiveProfileCwap > Instrument.MasterInstrument.RoundToTickSize(GetCurrentBid()))
					{
						
						
						// Now check where our planned stop is - is the Vwap > Cwap
						
						if (OFAIndicatorSTProfile1.OFAActiveProfileVwap > OFAIndicatorSTProfile1.OFAActiveProfileCwap)
						{
							// Enter Short Limit with an offset of 1 tick
							
							EnterShortLimit(OFAIndicatorSTProfile1.OFAActiveProfileCwap - (EntryOffset)*TickSize);
						}
					}
					
				}
			}
			
		}
		
		#region Properties
		[Range(1, int.MaxValue)]
		[NinjaScriptProperty]
		[Display(Name="StopLossTicks", Description="Numbers of ticks away from entry price for the Stop Loss order", Order=1, GroupName="Parameters")]
		public int StopLossTicks
		{ get; set; }

		[Range(1, int.MaxValue)]
		[NinjaScriptProperty]
		[Display(Name="ProfitTargetTicks", Description="Number of ticks away from entry price for the Profit Target order", Order=2, GroupName="Parameters")]
		public int ProfitTargetTicks
		{ get; set; }
		
		[Range(1, int.MaxValue)]
		[NinjaScriptProperty]
		[Display(Name="StopBreakEvenTicks", Description="Number of ticks profit to move stop to breakeven", Order=3, GroupName="Parameters")]
		public int StopBreakEvenTicks
		{ get; set; }
		
		[Range(1, int.MaxValue)]
		[NinjaScriptProperty]
		[Display(Name="RiskToleranceTicks", Description="Max number of ticks risk for trade", Order=4, GroupName="Parameters")]
		public int RiskToleranceTicks
		{ get; set; }
		
		[NinjaScriptProperty]
		[Range(1, int.MaxValue)]
		[Display(Name="EntryOffset", Order=5, GroupName="Parameters")]
		public int EntryOffset
		{ get; set; }
		
		[NinjaScriptProperty]
		[Range(1, int.MaxValue)]
		[Display(Name="StopOffset", Order=6, GroupName="Parameters")]
		public int StopOffset
		{ get; set; }
		
		[NinjaScriptProperty]
		//[Range(1, int.MaxValue)]
		[Display(Name="RunOnce Option", Order=7, GroupName="Parameters")]
		public bool RunOnce
		{ get; set; }
		
		#endregion
	}
}
