private static TWPosition FindTWPosition(string account, Position pos) { // this loop could be eliminated if the long symbol name gets persisted in database foreach (KeyValuePair <string, TWPosition> p in twpositions[account]) { TWPosition twpos = p.Value; if ((pos.Symbol == twpos.Symbol) && (pos.Type == twpos.Type) && (pos.Strike == twpos.Strike) && (pos.ExpDate == twpos.ExpDate)) { return(twpos); } } return(null); }
private static decimal DefaultCapital(string account, string strat, Positions positions) { decimal multiplier = 100; TWPosition twpos = FindTWPosition(account, positions.ElementAt(0).Value); if (twpos != null) { multiplier = twpos.Multiplier; } if (strat.Length >= 8) { strat = strat.Substring(0, 8); if ((strat == "Iron Con") || (strat == "Vertical")) { Dictionary <string, decimal> strikeRange = new Dictionary <string, decimal> { { "Call", 0 }, { "Put", 0 } }; foreach (KeyValuePair <string, Position> item in positions) { Position p = item.Value; strikeRange[p.Type] += (p.Strike * p.Quantity); } if (Math.Abs(strikeRange["Put"]) > Math.Abs(strikeRange["Call"])) { return(Math.Abs(strikeRange["Put"]) * multiplier); } else { return(Math.Abs(strikeRange["Call"]) * multiplier); } } } return(0); }
public static TWPositions Positions(string accountNumber) { Dictionary <string, decimal> marketValues = new Dictionary <string, decimal>(); Dictionary <string, Int32> orderIds = new Dictionary <string, Int32>(); SetHeaders(Token); // retrieve current values string reply = Web.DownloadString("https://api.tastyworks.com/margin/accounts/" + accountNumber); JObject package = JObject.Parse(reply); List <JToken> list = package["data"]["underlyings"].Children().ToList(); foreach (JToken item in list) { // capture the value of all of the options plus the underlaying JToken prices = item["marks"]; foreach (JProperty price in prices) { if (!marketValues.ContainsKey(price.Name)) { marketValues.Add(price.Name, Convert.ToDecimal(price.Value)); } } // capture any orders associated with the underlying string symbol = item["underlying-symbol"].ToString(); JToken orders = item["order-ids"]; for (int i = 0; i < orders.Count(); i++) { if (!orderIds.ContainsKey(symbol)) { Int32 order = Convert.ToInt32(orders[i]); orderIds.Add(symbol, order); } } } SetHeaders(Token); // reset, lost after previous call // retrieve specific positions reply = Web.DownloadString("https://api.tastyworks.com/accounts/" + accountNumber + "/positions"); package = JObject.Parse(reply); TWPositions returnList = new TWPositions(); list = package["data"]["items"].Children().ToList(); foreach (JToken item in list) { TWPosition inst = new TWPosition(); inst.Symbol = item["underlying-symbol"].ToString(); inst.OptionSymbol = item["symbol"].ToString(); inst.Quantity = Convert.ToDecimal(item["quantity"]); if (item["quantity-direction"].ToString() == "Short") { inst.Quantity *= -1; } DateTime exp = Convert.ToDateTime(item["expires-at"]).Trim(TimeSpan.TicksPerDay); inst.PreviousClose = Convert.ToDecimal(item["close-price"]); if (inst.PreviousClose == 0) { inst.PreviousClose = Convert.ToDecimal(item["average-open-price"]); } inst.Multiplier = Convert.ToDecimal(item["multiplier"]);; if (marketValues.ContainsKey(inst.OptionSymbol)) { inst.Market = marketValues[inst.OptionSymbol] * inst.Multiplier; } if (marketValues.ContainsKey(inst.Symbol)) { inst.UnderlyingPrice = marketValues[inst.Symbol]; } inst.OrderActive = orderIds.ContainsKey(inst.Symbol); SymbolDecoder symbol = new SymbolDecoder(inst.OptionSymbol, item["instrument-type"].ToString()); inst.Type = symbol.Type; inst.ExpDate = symbol.Expiration; inst.Strike = symbol.Strike; returnList.Add(inst.OptionSymbol.Length > 0 ? inst.OptionSymbol : inst.Symbol, inst); } return((returnList.Count > 0) ? returnList : null); }
public string ValidateCurrentHoldings() { string returnValue = ""; Dictionary <string, TWPositions> overallPositions = null; // always start with clean data if (TastyWorks.ActiveSession()) { overallPositions = new Dictionary <string, TWPositions>(); foreach (Account a in accounts) { if (a.Active) { // retrieve Tastyworks positions for given account TWPositions pos = TastyWorks.Positions(a.ID); overallPositions.Add(a.ID, pos); } } } else { MessageBox.Show("Login to TastyWorks failed", "Error"); return("LoginFailed"); } foreach (KeyValuePair <string, TWPositions> item in overallPositions) { // cycle thru each account TWPositions accountPositions = item.Value; // skip if the account is empty of positions // and confirm each aligns with what is in current database by // iterating thru all the positions in the current account // int i = 0; while ((accountPositions != null) && (i < accountPositions.Count)) { TWPosition position = accountPositions.ElementAt(i).Value; // iterate thru each group foreach (KeyValuePair <int, TransactionGroup> grpItem in this) { TransactionGroup grp = grpItem.Value; // examine closer if right account and underlying if ((item.Key == grp.Account) && (position.Symbol == grp.Symbol)) { // iterate thru everthing in the group int j = 0; while ((j < grp.Holdings.Count) && (position.Quantity != 0)) { Position dbpos = grp.Holdings[grp.Holdings.Keys.ElementAt(j)]; // look for matching security if ((position.Type == dbpos.Type) && (position.Strike == dbpos.Strike) && (position.ExpDate == dbpos.ExpDate)) { position.Quantity -= dbpos.Quantity; grp.Holdings.Remove(grp.Holdings.Keys.ElementAt(j)); } else { j++; } } } } if (position.Quantity == 0) { accountPositions.Remove(accountPositions.ElementAt(i).Key); } else { i++; } } } // catch anything left over in database foreach (KeyValuePair <int, TransactionGroup> grpItem in this) { TransactionGroup grp = grpItem.Value; if (grp.Holdings.Count > 0) { // something left if (returnValue.Length == 0) { returnValue = "Unmatched positons in the database:\n"; } returnValue += grp.Holdings.ToString(); } } // add anything left from the TW query foreach (KeyValuePair <string, TWPositions> positionsPair in overallPositions) { bool firstPass = true; // nothing to do if account is empty if (positionsPair.Value != null) { foreach (KeyValuePair <string, TWPosition> p in positionsPair.Value) { TWPosition pos = p.Value; if (firstPass) { firstPass = false; if (returnValue.Length > 0) { returnValue += "\n"; } returnValue += "Unmatched from TastyWorks account:\n"; } returnValue += (pos.Type == "Stock") ? pos.Symbol : pos.Symbol + pos.ExpDate.ToString("yyMMdd") + pos.Strike.ToString("0000.0") + pos.Type + " : " + pos.Quantity.ToString() + "\n"; } } } return(returnValue); }
private void RetrieveCurrentData(TransactionGroup grp) { decimal currentValue = 0; decimal previousCloseValue = 0; try { // retrieve and cache current data from tastyworks for this a subsequent passes if (twpositions == null) { if (TastyWorks.ActiveSession()) { List <string> symbols = new List <string>(); twpositions = new Dictionary <string, TWPositions>(); foreach (Account a in accounts) { if (a.Active) { // retrieve Tastyworks positions for given account TWPositions pos = TastyWorks.Positions(a.ID); twpositions.Add(a.ID, pos); if (pos != null) { foreach (KeyValuePair <string, TWPosition> p in pos) { if (!symbols.Contains(p.Value.Symbol)) { symbols.Add(p.Value.Symbol); } } } } } twmarketinfo = TastyWorks.MarketInfo(symbols); // get IV's } } // ensure that positions got instanciated AND that the particular account isn't empty if ((twpositions != null) && (twpositions.Count > 0) && (twpositions[grp.Account] != null)) { foreach (KeyValuePair <string, Position> item in grp.Holdings) { Position pos = item.Value; // this loop could be eliminated if the long symbol name gets persisted in database foreach (KeyValuePair <string, TWPosition> p in twpositions[grp.Account]) { TWPosition twpos = p.Value; if ((pos.Symbol == twpos.Symbol) && (pos.Type == twpos.Type) && (pos.Strike == twpos.Strike) && (pos.ExpDate == twpos.ExpDate)) { //Debug.WriteLine(twpos.Market); currentValue += pos.Quantity * twpos.Market; previousCloseValue += pos.Quantity * twpos.PreviousClose * twpos.Multiplier; // capture current details while we have it pos.Market = twpos.Market; pos.Multiplier = twpos.Multiplier; pos.UnderlyingPrice = twpos.UnderlyingPrice; // capture the underlying price from the first position for the overall group if (grp.UnderlyingPrice == 0) { grp.UnderlyingPrice = twpos.UnderlyingPrice; } // update groups order status based on any of items constituent holdings grp.OrderActive = twpos.OrderActive; } } } } grp.CurrentValue = currentValue; grp.PreviousCloseValue = previousCloseValue; grp.ChangeFromPreviousClose = currentValue - previousCloseValue; if (twmarketinfo.ContainsKey(grp.ShortSymbol)) { grp.ImpliedVolatility = twmarketinfo[grp.ShortSymbol].ImpliedVolatility; grp.ImpliedVolatilityRank = twmarketinfo[grp.ShortSymbol].ImpliedVolatilityRank; grp.DividendYield = twmarketinfo[grp.ShortSymbol].DividendYield; } } catch (Exception ex) { Debug.WriteLine("RetrieveCurrentData: " + ex.Message); } }