private void GetHistoryHelper(HistoryRequest request, Resolution resolution) { var brokerage = new TradierBrokerage(null, null, null, null, _useSandbox, _accountId, _accessToken); var requests = new[] { request }; var history = brokerage.GetHistory(requests, TimeZones.Utc); foreach (var slice in history) { if (resolution == Resolution.Tick) { foreach (var tick in slice.Ticks[request.Symbol]) { Log.Trace("{0}: {1} - {2} / {3}", tick.Time, tick.Symbol, tick.BidPrice, tick.AskPrice); } } else { var bar = slice.Bars[request.Symbol]; Log.Trace("{0}: {1} - O={2}, H={3}, L={4}, C={5}, V={6}", bar.Time, bar.Symbol, bar.Open, bar.High, bar.Low, bar.Close, bar.Volume); } } Log.Trace("Data points retrieved: " + brokerage.DataPointCount); }
public void GetsHistory(Symbol symbol, Resolution resolution, TimeSpan period, bool throwsException) { TestDelegate test = () => { var useSandbox = Config.GetBool("tradier-use-sandbox"); var accountId = Config.Get("tradier-account-id"); var accessToken = Config.Get("tradier-access-token"); var brokerage = new TradierBrokerage(null, null, null, useSandbox, accountId, accessToken); var now = DateTime.UtcNow; var requests = new[] { new HistoryRequest(now.Add(-period), now, typeof(QuoteBar), symbol, resolution, SecurityExchangeHours.AlwaysOpen(TimeZones.EasternStandard), TimeZones.EasternStandard, Resolution.Minute, false, false, DataNormalizationMode.Adjusted, TickType.Quote) }; var history = brokerage.GetHistory(requests, TimeZones.Utc); foreach (var slice in history) { if (resolution == Resolution.Tick) { foreach (var tick in slice.Ticks[symbol]) { Log.Trace("{0}: {1} - {2} / {3}", tick.Time, tick.Symbol, tick.BidPrice, tick.AskPrice); } } else { var bar = slice.Bars[symbol]; Log.Trace("{0}: {1} - O={2}, H={3}, L={4}, C={5}, V={6}", bar.Time, bar.Symbol, bar.Open, bar.High, bar.Low, bar.Close, bar.Volume); } } Log.Trace("Data points retrieved: " + brokerage.DataPointCount); }; if (throwsException) { Assert.Throws <ArgumentException>(test); } else { Assert.DoesNotThrow(test); } }
/******************************************************** * CONSTRUCTOR *********************************************************/ /// <summary> /// Constructor for the tradier transaction handler /// </summary> /// <param name="algorithm">Algorithm instance</param> /// <param name="brokerage">Brokerage instance</param> /// <param name="results">Result handler </param> /// <param name="accountId">Tradier account id</param> public TradierTransactionHandler(IAlgorithm algorithm, IBrokerage brokerage, IResultHandler results, int accountId) { _algorithm = algorithm; _isActive = true; _ready = false; _accountId = accountId; //Connect with Tradier: _tradier = (TradierBrokerage)brokerage; _results = results; }
public void GetsHistory(Symbol symbol, Resolution resolution, TimeSpan period, bool throwsException) { TestDelegate test = () => { var accessToken = Config.Get("tradier-access-token"); var brokerage = new TradierBrokerage(null, null, ""); brokerage.SetTokens(0, accessToken, "", DateTime.Now, Time.OneDay); var now = DateTime.UtcNow; var requests = new[] { new HistoryRequest { Symbol = symbol, Resolution = resolution, StartTimeUtc = now.Add(-period), EndTimeUtc = now } }; var history = brokerage.GetHistory(requests, TimeZones.Utc); foreach (var slice in history) { if (resolution == Resolution.Tick) { foreach (var tick in slice.Ticks[symbol]) { Log.Trace("{0}: {1} - {2} / {3}", tick.Time, tick.Symbol, tick.BidPrice, tick.AskPrice); } } else { var bar = slice.Bars[symbol]; Log.Trace("{0}: {1} - O={2}, H={3}, L={4}, C={5}, V={6}", bar.Time, bar.Symbol, bar.Open, bar.High, bar.Low, bar.Close, bar.Volume); } } Log.Trace("Data points retrieved: " + brokerage.DataPointCount); }; if (throwsException) { Assert.Throws <ArgumentException>(test); } else { Assert.DoesNotThrow(test); } }
/// <summary> /// Creates the brokerage under test /// </summary> /// <returns>A connected brokerage instance</returns> protected override IBrokerage CreateBrokerage(IOrderProvider orderProvider, ISecurityProvider securityProvider) { var accountID = TradierBrokerageFactory.Configuration.AccountID; var tradier = new TradierBrokerage(orderProvider, securityProvider, accountID); var qcUserID = TradierBrokerageFactory.Configuration.QuantConnectUserID; var tokens = TradierBrokerageFactory.GetTokens(); tradier.SetTokens(qcUserID, tokens.AccessToken, tokens.RefreshToken, tokens.IssuedAt, TimeSpan.FromSeconds(tokens.ExpiresIn)); // keep the tokens up to date in the event of a refresh tradier.SessionRefreshed += (sender, args) => { File.WriteAllText(TradierBrokerageFactory.TokensFile, JsonConvert.SerializeObject(args, Formatting.Indented)); }; return(tradier); }
/******************************************************** * CLASS CONSTRUCTOR *********************************************************/ /// <summary> /// Tradier datafeed handler for getting free data from the tradier brokerage api. /// </summary> /// <param name="algorithm">Algorithm requesting data</param> /// <param name="job">Job packet requesting data</param> /// <param name="brokerage">Brokerage instance to avoid access token duplication.</param> public TradierDataFeed(IAlgorithm algorithm, IBrokerage brokerage, LiveNodePacket job) { //Subscription Count: _subscriptions = algorithm.SubscriptionManager.Subscriptions; _subscriptionCount = Subscriptions.Count; //Set Properties: _dataFeed = DataFeedEndpoint.Tradier; _isActive = true; _bridge = new ConcurrentQueue <List <BaseData> > [_subscriptionCount]; _endOfBridge = new bool[_subscriptionCount]; _subscriptionManagers = new SubscriptionDataReader[_subscriptionCount]; //Class Privates: _job = job; _algorithm = algorithm; //Setup the arrays: for (var i = 0; i < _subscriptionCount; i++) { _endOfBridge[i] = false; _bridge[i] = new ConcurrentQueue <List <BaseData> >(); //This is quantconnect data source, store here for speed/ease of access _isQuantConnectData.Add(algorithm.Securities[_subscriptions[i].Symbol].IsQuantConnectData); //Subscription managers for downloading user data: _subscriptionManagers[i] = new SubscriptionDataReader(_subscriptions[i], algorithm.Securities[_subscriptions[i].Symbol], DataFeedEndpoint.LiveTrading, new DateTime(), new DateTime(9999, 12, 12)); //Set up the source file for today: _subscriptionManagers[i].RefreshSource(DateTime.Now.Date); } //Setup Brokerage Access: _tradier = (TradierBrokerage)brokerage; }
/// <summary> /// Creates a new IBrokerage instance /// </summary> /// <param name="job">The job packet to create the brokerage for</param> /// <param name="algorithm">The algorithm instance</param> /// <returns>A new brokerage instance</returns> public override IBrokerage CreateBrokerage(LiveNodePacket job, IAlgorithm algorithm) { var errors = new List <string>(); var accountID = Read <long>(job.BrokerageData, "tradier-account-id", errors); var accessToken = Read <string>(job.BrokerageData, "tradier-access-token", errors); var refreshToken = Read <string>(job.BrokerageData, "tradier-refresh-token", errors); var issuedAt = Read <DateTime>(job.BrokerageData, "tradier-issued-at", errors); var lifeSpan = TimeSpan.FromSeconds(Read <double>(job.BrokerageData, "tradier-lifespan", errors)); var brokerage = new TradierBrokerage(algorithm.Transactions, algorithm.Portfolio, accountID); // if we're running live locally we'll want to save any new tokens generated so that they can easily be retrieved if (Config.GetBool("tradier-save-tokens")) { brokerage.SessionRefreshed += (sender, args) => { File.WriteAllText(TokensFile, JsonConvert.SerializeObject(args, Formatting.Indented)); }; } brokerage.SetTokens(job.UserId, accessToken, refreshToken, issuedAt, lifeSpan); return(brokerage); }
/// <summary> /// Primary entry point to setup a new algorithm /// </summary> /// <param name="algorithm">Algorithm instance</param> /// <param name="brokerage">New brokerage output instance</param> /// <param name="baseJob">Algorithm job task</param> /// <returns>True on successfully setting up the algorithm state, or false on error.</returns> public bool Setup(IAlgorithm algorithm, out IBrokerage brokerage, AlgorithmNodePacket baseJob) { //-> Initialize: var initializeComplete = false; var job = baseJob as LiveNodePacket; var portfolioResolution = PortfolioResolution(algorithm.Securities); //-> Connect to Tradier: _tradier = new TradierBrokerage(); //_tradier = (Tradier)brokerage; _tradier.SetTokens(job.UserId, job.AccessToken, job.RefreshToken, job.IssuedAt, job.LifeTime); brokerage = _tradier; // -> Refresh the session immediately, buy us 24 hours: if (!_tradier.RefreshSession()) { Errors.Add("Failed to refresh access token. Please login again."); return(false); } //-> Setup any user specific code: try { algorithm.Initialize(); } catch (Exception err) { Errors.Add("Failed to initialize user algorithm, Initialize() returned error - " + err.Message); return(false); } Log.Trace("TradierSetupHandler.Setup(): Algorithm initialized"); //-> Strip any FOREX Symbols: var symbols = algorithm.Securities.Keys.ToList(); foreach (var symbol in symbols) { if (algorithm.Securities[symbol].Type == SecurityType.Forex) { algorithm.Securities.Remove(symbol); } } //-> Fetch the orders on the account: var orders = _tradier.FetchOrders(job.AccountId); foreach (var order in orders) { //Ignore option orders for now. if (order.Class != TradierOrderClass.Equity) { continue; } var qcPrice = order.Price; var qcQuantity = order.Quantity; var qcType = OrderType.Limit; var qcStatus = OrderStatus.None; // Get the order type: switch (order.Type) { case TradierOrderType.Market: qcType = OrderType.Market; break; case TradierOrderType.Limit: qcType = OrderType.Limit; break; case TradierOrderType.StopMarket: qcType = OrderType.StopMarket; break; } // Convert order direction to a quantity switch (order.Direction) { case TradierOrderDirection.Buy: case TradierOrderDirection.BuyToCover: break; case TradierOrderDirection.Sell: case TradierOrderDirection.SellShort: qcQuantity *= -1; //Invert quantity. break; } //Set the QC Order Status Flag: switch (order.Status) { case TradierOrderStatus.Canceled: qcStatus = OrderStatus.Canceled; break; case TradierOrderStatus.Filled: qcStatus = OrderStatus.Filled; break; case TradierOrderStatus.Open: case TradierOrderStatus.Submitted: case TradierOrderStatus.Pending: qcStatus = OrderStatus.Submitted; break; case TradierOrderStatus.PartiallyFilled: qcStatus = OrderStatus.PartiallyFilled; break; case TradierOrderStatus.Rejected: qcStatus = OrderStatus.Invalid; break; } //Create the new qcOrder var qcOrder = new Order(order.Symbol, Convert.ToInt32((decimal)qcQuantity), qcType, order.CreatedDate, qcPrice); //Set Status for Order: qcOrder.Status = qcStatus; //Create any fill information: var fill = new OrderEvent(qcOrder, "Pre-existing Tradier Order"); fill.FillPrice = order.AverageFillPrice; fill.FillQuantity = Convert.ToInt32((decimal)order.QuantityExecuted); var fillList = new List <OrderEvent>() { fill }; //Get a unique qc-id: set to fill var qcid = algorithm.Transactions.GetIncrementOrderId(); order.Id = qcid; fill.OrderId = qcid; qcOrder.Id = qcid; //Add the order to our internal records: algorithm.Transactions.Orders.AddOrUpdate <int, Order>(Convert.ToInt32((long)order.Id), qcOrder); //Add the fill quantity to the list: algorithm.Transactions.OrderEvents.AddOrUpdate <int, List <OrderEvent> >(Convert.ToInt32((long)order.Id), fillList); //If we don't have this symbol, add it manually: if (!algorithm.Portfolio.ContainsKey(order.Symbol)) { algorithm.AddSecurity(SecurityType.Equity, order.Symbol, portfolioResolution, true, 1, false); } } //-> Retrieve/Set Tradier Portfolio Positions: var positions = _tradier.Positions(job.AccountId); foreach (var position in positions) { //We can't support options. if (position.Symbol.Length >= 10) { continue; } //If we don't have this symbol, add it manually: if (!algorithm.Portfolio.ContainsKey(position.Symbol)) { algorithm.AddSecurity(SecurityType.Equity, position.Symbol, portfolioResolution, true, 1, false); } //Once we have the symbol, set the holdings: var avgPrice = Math.Round(position.CostBasis / Convert.ToDecimal((long)position.Quantity), 4); algorithm.Portfolio[position.Symbol].SetHoldings(avgPrice, (int)position.Quantity); Log.Trace("TradierSetupHandler.Setup(): Portfolio security added to algorithm: " + position.Symbol + " with " + position.Quantity + " shares at " + avgPrice.ToString("C")); } //-> Retrieve/Set Tradier Cash Positions: var balanceFound = false; //HACK: //balanceFound = true; //algorithm.Portfolio.SetCash(100000); //_startingCapital = 100000; var balance = _tradier.Balance(job.AccountId); if (balance != null) { if (balance.AccountNumber == job.AccountId) { //Set the cash in this account: var cash = balance.TotalCash - balance.OptionRequirement; algorithm.Portfolio.SetCash(cash); StartingCapital = cash; balanceFound = true; Log.Trace("TradierSetupHandler.Setup(): Free Cash: " + cash.ToString("C")); Log.Trace("TradierSetupHandler.Setup(): Total Cash: " + balance.TotalCash.ToString("C")); } //Set the leverage on all the securities: switch (balance.Type) { //Maximum 1x Leverage case TradierAccountType.Cash: foreach (var security in algorithm.Securities.Values) { if (security.Type == SecurityType.Equity) { security.SetLeverage(1m); } } break; //Maximum 2x Leverage case TradierAccountType.Margin: foreach (var security in algorithm.Securities.Values) { if (security.Type == SecurityType.Equity && security.Leverage > 2) { security.SetLeverage(2m); } } break; case TradierAccountType.DayTrader: //Do nothing, let the user set their own leverage: foreach (var security in algorithm.Securities.Values) { if (security.Type == SecurityType.Equity && security.Leverage > 4) { security.SetLeverage(4m); } } break; } } // Maximum number of orders or the algorithm MaxOrders = int.MaxValue; if (!balanceFound) { Errors.Add("Could not get the account cash balance"); } if (Errors.Count == 0) { initializeComplete = true; } return(initializeComplete); }