using System;
using ZuluTradingSampleApp.Configuration;
using ZuluTradingSampleApp.Model;
using ZuluTradingSampleApp.Trading;
using ZuluTradingSampleApp.Utils;

namespace ZuluTradingSampleApp
{
    class ZuluTradingSampleApp
    {
        static void Main()
        {
            ZuluTradingServerConfig cfg = new ZuluTradingServerConfig("http://tradingserver.zulutrade.com/");
            ZuluTradeAuthenticationInfo ai = new ZuluTradeAuthenticationInfo("yourZuluAccountUsername", "yourZuluAccountPassword");

            IZuluTradingGateway tradingGateway = new ZuluTradingGatewayImpl(ai, cfg);

            //Getting minimum trading amount and amount step for account
            try
            {
                TradingConfigurationResponseMessage tradingConfiguration = tradingGateway.GetTradingConfiguration();

                Console.WriteLine("Account's trading configuration: ");
                Console.Write("Minimum amount for trading: " +tradingConfiguration.MinAmount+ " lots");
                Console.Write(", Minimum amount step for trading: " + tradingConfiguration.MinAmountStep + " lots");
                Console.WriteLine("\n");
            }
            catch (Exception e) 
            {
                Console.Error.WriteLine(e.StackTrace);
            }


            //Getting current open trades/orders
            try
            {
                OpenTradesResponseMessage openTrades = tradingGateway.GetOpenTrades();

                Console.WriteLine("Open market trades: ");
                Console.WriteLine("Total: " + openTrades.OpenPositions.Count);
                foreach (NewMarketTradeResponseMessage marketTrade in openTrades.OpenPositions)
                {
                    Console.Write("provider ticket: " + marketTrade.UniqueId);
                    Console.Write(" broker ticket: " + marketTrade.BrokerTicket);
                    Console.Write(", currency: " + marketTrade.CurrencyName);
                    Console.Write(", lots: " + marketTrade.Lots);
                    Console.Write(", rate: " + marketTrade.EntryRate);
                    Console.Write(", stop: " + marketTrade.StopValue);
                    Console.Write(", trailing stop: " + marketTrade.TrailingStopValue);
                    Console.Write(", trailing stop condition pips: " + marketTrade.TrailingStopConditionPipsValue);
                    Console.Write(", limit: " + marketTrade.LimitValue);
                    Console.Write(", floatingPnL: " + marketTrade.FloatingPnl);
                    Console.WriteLine();
                }

                Console.WriteLine();
                Console.WriteLine("Pending orders: ");
                Console.WriteLine("Total: " + openTrades.OpenOrders.Count);
                foreach (NewOrderResponseMessage pendingOrder in openTrades.OpenOrders)
                {
                    Console.Write("provider ticket: " + pendingOrder.UniqueId);
                    Console.Write(" broker ticket: " + pendingOrder.BrokerTicket);
                    Console.Write(", currency: " + pendingOrder.CurrencyName);
                    Console.Write(", lots: " + pendingOrder.Lots);
                    Console.Write(", rate: " + pendingOrder.EntryRate);
                    Console.Write(", stop: " + pendingOrder.StopValue);
                    Console.Write(", trailing stop: " + pendingOrder.TrailingStopValue);
                    Console.Write(", trailing stop condition pips: " + pendingOrder.TrailingStopConditionPipsValue);
                    Console.Write(", limit: " + pendingOrder.LimitValue);
                    Console.WriteLine();
                }
            }
            catch (Exception e)
            {
                Console.Error.WriteLine(e.StackTrace);
            }

            /* 
             * Opening a market order and 
             * setting stop loss, trailing stop, trailing stop condtion pips, take profit and 
             * closing example
             */
            try
            {

                String uniqueId = UniqueIdGenerator.GetNextUniqueId();
                
                Console.WriteLine();
                Console.WriteLine("\nOpening trade, uniqueId to use: " + uniqueId);

                double entryRateToUse = 1.4;
                NewMarketTradeResponseMessage openResponse = tradingGateway.OpenMarket("EUR/USD", 1, true, entryRateToUse, uniqueId);

                if (openResponse.Success)
                {
                    Console.WriteLine("\tTrade opened, unique id: " + openResponse.UniqueId
                            + ", brokerTicket: " + openResponse.BrokerTicket + ", entry rate: " + openResponse.EntryRate + ", utc date opened: " + openResponse.DateOpened + ", timestamp: " + openResponse.OpenUtcTimestamp);

                    double stopLossToSet = 1.0;

                    Console.WriteLine("Setting stop loss to " + stopLossToSet);

                    UpdateValueResponseMessage updateResponse = tradingGateway.UpdateStop("EUR/USD", true, 1, uniqueId, stopLossToSet);

                    if (updateResponse.Success)
                    {
                        Console.WriteLine("\tSuccess: new " + updateResponse.ValueType + " value " + updateResponse.NewValue);
                    }
                    else
                    {
                        Console.Error.WriteLine("\tFailure: could not set stop loss, error message: " + updateResponse.ErrorMessage + ", error code: " + updateResponse.ErrorCode);
                    }

                    int trailingStopValueToSet = 1000;
                    
                    Console.WriteLine("Setting trailing stop value to " + trailingStopValueToSet);

                    UpdateTrailingStopValueResponseMessage updateTrailingStopResponse = tradingGateway.UpdateTrailingStop("EUR/USD", true, 1, uniqueId, trailingStopValueToSet);

                    if (updateTrailingStopResponse.Success)
                    {
                        Console.WriteLine("\tSuccess: new " + updateTrailingStopResponse.ValueType + " value set at " + updateTrailingStopResponse.NewTrailingStopValue + " pips. New stop value: " + updateTrailingStopResponse.NewStopValue);
                    }
                    else
                    {
                        Console.WriteLine("\tFailure: could not set trailing stop, error message: " + updateTrailingStopResponse.ErrorMessage + ", error code: " + updateResponse.ErrorCode);
                    }

                    trailingStopValueToSet = 700;
                    int tralingStopConditionPipsToSet = 800;

                    Console.WriteLine("Setting trailing stop conditions value to "+tralingStopConditionPipsToSet+" and trailing stop value to "+trailingStopValueToSet);

                    UpdateTrailingStopValueResponseMessage updateTrailingStopConditionResponse = tradingGateway.UpdateTrailingStopCondition("EUR/USD", true, 1, uniqueId, trailingStopValueToSet, tralingStopConditionPipsToSet);
                    if (updateTrailingStopConditionResponse.Success)
                    {
                        Console.WriteLine("\tSuccess: new " + updateTrailingStopConditionResponse.ValueType + " value set at " + updateTrailingStopConditionResponse.NewTrailingStopConditionValue + " pips. Trailing Stop value that will be set when " + updateTrailingStopConditionResponse.ValueType + " is reached is: " + updateTrailingStopConditionResponse.NewTrailingStopValue);
                    }
                    else
                    {
                        Console.Error.WriteLine("\tFailure: could not set trailing stop condition pips, error message: " + updateTrailingStopConditionResponse.ErrorMessage + ", error code: " + updateTrailingStopConditionResponse.ErrorCode);
                    }

                    double takeProfitToSet = 2.1;

                    Console.WriteLine("Setting take profit to " + takeProfitToSet);

                    updateResponse = tradingGateway.UpdateLimit("EUR/USD", true, 1, uniqueId, takeProfitToSet);

                    if (updateResponse.Success)
                    {
                        Console.WriteLine("\tSuccess: new " + updateResponse.ValueType + " value " + updateResponse.NewValue);
                    }
                    else
                    {
                        Console.Error.WriteLine("\tFailure: could not set take profit, error message: " + updateResponse.ErrorMessage + ", error code: " + updateResponse.ErrorCode);
                    }

                    Console.WriteLine("Closing trade");

                    TradeClosedResponseMessage closedResponse = tradingGateway.CloseMarket("EUR/USD", 1, true, uniqueId, entryRateToUse);

                    if (closedResponse.Success)
                    {
                        Console.Write("\tTrade closed" + ", ");
                        Console.Write("price open: " + closedResponse.PriceOpen + ", ");
                        Console.Write("price closed: " + closedResponse.PriceClosed + ", ");
                        Console.Write("date open: " + closedResponse.DateOpen + ", ");
                        Console.Write("open timestamp: " + closedResponse.OpenUtcTimestamp + ", ");
                        Console.Write("date closed: " + closedResponse.DateClosed + ", ");
                        Console.Write("close timestamp: " + closedResponse.CloseUtcTimestamp + ", ");
                        Console.Write("gross pnl: " + closedResponse.GrossPnl + ", ");
                        Console.Write("interest: " + closedResponse.Interest + ", ");
                        Console.Write("commission :" + closedResponse.Commission + ", ");
                        Console.WriteLine("net pnl: " + closedResponse.NetPnl);
                    }
                    else
                    {
                        Console.Error.WriteLine("\tCould not close trade, error message: " + closedResponse.ErrorMessage + ", error code: " + updateResponse.ErrorCode);
                    }
                }
                else
                {
                    Console.Error.WriteLine("\tCould not open trade, response: " + openResponse.ErrorMessage + ", error code: " + openResponse.ErrorCode);
                }
            }
            catch (Exception ex)
            {
                Console.Error.WriteLine(ex.StackTrace);
            }

         /*
		 * Opening a pending order
		 * and setting stop loss, trailing stop, trailing stop condtion pips, take profit, entry rate 
		 * and canceling example
		 */
            try
            {
                String uniqueId = UniqueIdGenerator.GetNextUniqueId();

                double entryRateToUse = 1.4;
                Console.WriteLine();
                Console.WriteLine("Openning pending order, uniqueId to use: " + uniqueId + ", target entry rate: " + entryRateToUse);

                NewOrderResponseMessage openResponse = tradingGateway.OpenOrder("EUR/USD", 1, true, entryRateToUse, uniqueId);

                if (openResponse.Success)
                {
                    Console.WriteLine("\tPending order placed, unique id: " + openResponse.UniqueId
                            + ", brokerTicket: " + openResponse.BrokerTicket + ", entry rate: " + openResponse.EntryRate);

                    double stopLossToSet = 0.9;

                    Console.WriteLine("Setting stop loss to " + stopLossToSet);

                    UpdateValueResponseMessage updateResponse = tradingGateway.UpdateStop("EUR/USD", true, 1, uniqueId, stopLossToSet);

                    if (updateResponse.Success)
                    {
                        Console.WriteLine("\tSuccess: new " + updateResponse.ValueType + " value " + updateResponse.NewValue);
                    }
                    else
                    {
                        Console.Error.WriteLine("\tFailure: could not set stop loss, error message: " + updateResponse.ErrorMessage);
                    }

                    int trailingStopValueToSet = 1000;

                    Console.WriteLine("Setting trailing stop value to " + trailingStopValueToSet);

                    UpdateTrailingStopValueResponseMessage updateTrailingStopResponse = tradingGateway.UpdateTrailingStop("EUR/USD", true, 1, uniqueId, trailingStopValueToSet);

                    if (updateTrailingStopResponse.Success)
                    {
                        Console.WriteLine("\tSuccess: new " + updateTrailingStopResponse.ValueType + " value set at " + updateTrailingStopResponse.NewTrailingStopValue + " pips. New stop value: " + updateTrailingStopResponse.NewStopValue);

                    }
                    else
                    {
                        Console.WriteLine("\tFailure: could not set trailing stop, error message: " + updateTrailingStopResponse.ErrorMessage + ", error code: " + updateResponse.ErrorCode);
                    }

                    trailingStopValueToSet = 700;
                    int tralingStopConditionPipsToSet = 800;

                    Console.WriteLine("Setting trailing stop conditions value to " + tralingStopConditionPipsToSet + " and trailing stop value to " + trailingStopValueToSet);

                    UpdateTrailingStopValueResponseMessage updateTrailingStopConditionResponse = tradingGateway.UpdateTrailingStopCondition("EUR/USD", true, 1, uniqueId, trailingStopValueToSet, tralingStopConditionPipsToSet);
                    if (updateTrailingStopConditionResponse.Success)
                    {
                        Console.WriteLine("\tSuccess: new " + updateTrailingStopConditionResponse.ValueType + " value set at " + updateTrailingStopConditionResponse.NewTrailingStopConditionValue + " pips. Trailing Stop value that will be set when " + updateTrailingStopConditionResponse.ValueType + " is reached is: " + updateTrailingStopConditionResponse.NewTrailingStopValue);
                    }
                    else
                    {
                        Console.Error.WriteLine("\tFailure: could not set trailing stop condition pips, error message: " + updateTrailingStopConditionResponse.ErrorMessage + ", error code: " + updateTrailingStopConditionResponse.ErrorCode);
                    }

                    double takeProfitToSet = 2.1;

                    Console.WriteLine("Setting take profit to " + takeProfitToSet);

                    updateResponse = tradingGateway.UpdateLimit("EUR/USD", true, 1, uniqueId, takeProfitToSet);

                    if (updateResponse.Success)
                    {
                        Console.WriteLine("\tSuccess: new " + updateResponse.ValueType + " value " + updateResponse.NewValue);
                    }
                    else
                    {
                        Console.Error.WriteLine("\tFailure: could not set take profit, error message: " + updateResponse.ErrorMessage);
                    }

                    double entryRateToUpdate = 1.5;

                    Console.WriteLine("Updating entry rate to " + entryRateToUpdate);

                    updateResponse = tradingGateway.UpdateEntryRate("EUR/USD", true, 1, uniqueId, entryRateToUpdate);

                    if (updateResponse.Success)
                    {
                        Console.WriteLine("\tSuccess: new " + updateResponse.ValueType + " value " + updateResponse.NewValue);
                    }
                    else
                    {
                        Console.Error.WriteLine("\tFailure: could not update entry rate, error message: " + updateResponse.ErrorMessage);
                    }

                    Console.WriteLine("Canceling trade");

                    OrderCanceledResponseMessage cancelResponse = tradingGateway.CancelOrder("EUR/USD", 1, true, uniqueId);

                    if (cancelResponse.Success)
                    {
                        Console.Write("\tPending order canceled" + ", ");
                        Console.WriteLine("date canceled: " + cancelResponse.DateCanceled);
                    }
                    else
                    {
                        Console.Error.WriteLine("\tCould not close trade, error message: " + cancelResponse.ErrorMessage);
                    }
                }
                else
                {
                    Console.Error.WriteLine("\tCould not open trade, response: " + openResponse.ErrorMessage);
                }
            }
            catch (Exception ex)
            {
                Console.Error.WriteLine(ex.StackTrace);
            }

            //Getting historic trades/orders example 
            try
            {
                string startDate = DateUtil.GetStartDate();
                string endDate = DateUtil.GetEndDate();
                Console.WriteLine("\n\nGetting yesterday's historic trades/orders (between " + startDate + " and " + endDate + ")");

                
                ClosedTradesResponseMessage historyTradesOrders = tradingGateway.GetHistory(startDate, endDate);
                if (historyTradesOrders.Success)
                {
                    Console.WriteLine("Closed trades: ");
                    Console.WriteLine("Total: " + historyTradesOrders.ClosedPositions.Count);
                    foreach (TradeClosedResponseMessage closedTrade in historyTradesOrders.ClosedPositions)
                    {
                        Console.Write("providerTicket: " +closedTrade.UniqueId);
					    Console.Write(", brokerTicket: " + closedTrade.BrokerTicket);
					    Console.Write(", currency: " + closedTrade.CurrencyName);
					    Console.Write(", lots: " +closedTrade.Lots);
					    Console.Write(", buy: " +closedTrade.Buy);
					    Console.Write(", PriceOpened: " +closedTrade.PriceOpen);
					    Console.Write(", PriceClosed: " +closedTrade.PriceClosed);
					    Console.Write(", DateOpened: " +closedTrade.DateOpen);
					    Console.Write(", openUtcTimeStamp: " +closedTrade.OpenUtcTimestamp);
					    Console.Write(", DateClosed: " +closedTrade.DateClosed);
					    Console.Write(", closeUtcTimeStamp: " +closedTrade.CloseUtcTimestamp);
					    Console.Write(", GrossPnl: " +closedTrade.GrossPnl);
					    Console.Write(", Commission: " +closedTrade.Commission);
					    Console.Write(", Interest: " +closedTrade.Interest);
					    Console.Write(", NetPnl: " +closedTrade.NetPnl);
                        Console.WriteLine();
                    }

                    Console.WriteLine("Canceled orders: ");
                    Console.WriteLine("Total: " + historyTradesOrders.CanceledOrders.Count);
                    foreach (OrderCanceledResponseMessage canceledOrder in historyTradesOrders.CanceledOrders)
                    { 
                        Console.Write("providerTicket: " +canceledOrder.UniqueId);
					    Console.Write(", brokerTicket: " +canceledOrder.BrokerTicket);
					    Console.Write(", currency: " +canceledOrder.CurrencyName);
					    Console.Write(", lots: " +canceledOrder.Lots);
					    Console.Write(", buy: " +canceledOrder.Buy);
					    Console.Write(", PriceOpened: "+canceledOrder.PriceOpen);
					    Console.Write(", DateOpened: " +canceledOrder.DateOpened);
					    Console.Write(", openedUtcTimestamp: " +canceledOrder.OpenedUtcTimestamp);
					    Console.Write(", DateCanceled: " +canceledOrder.DateCanceled);
					    Console.Write(", canceledUtcTimestamp: " +canceledOrder.CanceledUtcTimestamp);
                        Console.WriteLine();
                    }
                }
                else
                {
                    Console.Error.WriteLine("\tCould not get historic trades/orders, response: " + historyTradesOrders.ErrorMessage + ", error code: " + historyTradesOrders.ErrorCode);
                }
            }
            catch (Exception e)
            {
                Console.Error.WriteLine(e.StackTrace);
            }

            // Getting statistics of the account, if account is provider
            try
            {

                ProviderStatisticsResponseMessage providerStatisticsResponse = tradingGateway.GetProviderStatistics();

                Console.WriteLine("\n\nGetting provider's statistics: ");
			    if(providerStatisticsResponse.Success){
				    Console.WriteLine("Position in rank: " +providerStatisticsResponse.zuluRank);
				    Console.WriteLine("Amount Following: $" +providerStatisticsResponse.AmountFollowing);
				    Console.WriteLine("Profit: " +providerStatisticsResponse.Profit+ " pips");
				    Console.WriteLine("Weeks: " +providerStatisticsResponse.Weeks);
				    Console.WriteLine("Followers: " +providerStatisticsResponse.Followers);
				    Console.WriteLine("Trades: " +providerStatisticsResponse.Trades);
				    Console.WriteLine("Winning trades: " +providerStatisticsResponse.TotalWinTrades+ " ("+providerStatisticsResponse.TotalWinTradesPercent+"%)");
				    Console.WriteLine("Average pips/trade: " +providerStatisticsResponse.AvgPipsPerTrade);
				    Console.WriteLine("Average trade time: " +providerStatisticsResponse.AvgTradeTimeInSecs+ " seconds");
				    Console.WriteLine("Maximum Drawdown: " +providerStatisticsResponse.MaxDrawDownPercent +"% ("+providerStatisticsResponse.MaxDrawDown+")");
				    Console.WriteLine("Max Open Trades: " +providerStatisticsResponse.MaxOpenTrades);
				    Console.WriteLine("Worst Trade: " +providerStatisticsResponse.WorstTradePips+" pips");
				    Console.WriteLine("Best Trade: " +providerStatisticsResponse.BestTradePips+" pips");
				    Console.WriteLine("Has Live Followers: " +providerStatisticsResponse.HasLiveHollowers);
				    Console.WriteLine("Necessary Minimum Equity: $" +providerStatisticsResponse.NecessaryMinEquity);
				    Console.WriteLine("Statistics last updated in utc: " +providerStatisticsResponse.StatsLastUpdateDate+ ", timestamp: " +providerStatisticsResponse.StatsLastUpdateDateUtcTimeStamp);
                    Console.WriteLine();
			    }else{
                    Console.Error.WriteLine("\tFailure: could not get provider statistics, error message: " + providerStatisticsResponse.ErrorMessage + ", error code: " + providerStatisticsResponse.ErrorCode);
			    }
            }
            catch (Exception e)
            {
                Console.Error.WriteLine(e.StackTrace);
            }

            Console.WriteLine();
            Console.WriteLine("Press any key to exit...");
            Console.ReadKey();
        }
    }
}
