public Trade(Trade copy) { Id = copy.Id; FullSymbol = copy.FullSymbol; Account = copy.Account; TradeDate = copy.TradeDate; TradeTime = copy.TradeTime; TradePrice = copy.TradePrice; TradeSize = copy.TradeSize; }
public static Trade Deserialize(string tstr) { string[] ts = tstr.Split(','); if (ts.Length < 14) throw new Exception("Invalid trade"); Trade t = new Trade(); t.Id = Convert.ToInt64(ts[0], System.Globalization.CultureInfo.InvariantCulture); t.Account = ts[1]; t.TradeDate = Convert.ToInt32(ts[2], System.Globalization.CultureInfo.InvariantCulture); t.TradeTime = Convert.ToInt32(ts[3], System.Globalization.CultureInfo.InvariantCulture); t.FullSymbol = ts[4]; t.TradeSize = Convert.ToInt32(ts[5], System.Globalization.CultureInfo.InvariantCulture); t.TradePrice = Convert.ToDecimal(ts[6], System.Globalization.CultureInfo.InvariantCulture); return t; }
public decimal Adjust(Trade t) { return Adjust(new Position(t)); }
/// <summary> /// Gets the closed PL on a position basis, the PL that is registered to the account for the entire shares transacted. /// </summary> /// <param name="existing">The existing position.</param> /// <param name="closing">The portion of the position being changed/closed.</param> /// <returns></returns> public static decimal ClosePL(Position existing, Trade adjust) { int closedsize = Math.Abs(adjust.TradeSize) > existing.UnsignedSize ? existing.UnsignedSize : Math.Abs(adjust.TradeSize); return ClosePT(existing, adjust) * closedsize * Security.GetMultiplierFromFullSymbol(adjust.FullSymbol); }
public override void GotFill(Trade f) { Adjust(new Position(f)); }
public void GotFill(Trade f) { Adjust(f); }
void _backtestengine_GotFillEvent(Trade t) { _tradelist.Add(t); Position mypos = new Position(t); decimal closepnl = 0; decimal closepoint = 0; if (!_positionlist.TryGetValue(t.FullSymbol, out mypos)) { mypos = new Position(t); _positionlist.Add(t.FullSymbol, mypos); } else { closepoint = Calc.ClosePT(mypos, t); closepnl = mypos.Adjust(t); _positionlist[t.FullSymbol] = mypos; } System.Windows.Application.Current.Dispatcher.Invoke(() => { _positiontable.Rows.Add(t.TradeTime.ToString(), mypos.FullSymbol, mypos.Size, mypos.AvgPrice.ToString(_dps), closepnl.ToString("C2"), closepoint.ToString(_dps)); _filltable.Rows.Add(t.TradeTime.ToString(), t.FullSymbol, t.TradeSize, t.TradePrice.ToString(_dps), t.Id); }); }
public static string Serialize(Trade t) { string[] trade = new string[] { t.Id.ToString(System.Globalization.CultureInfo.InvariantCulture), t.Account, t.TradeDate.ToString(System.Globalization.CultureInfo.InvariantCulture), t.TradeTime.ToString(System.Globalization.CultureInfo.InvariantCulture), t.FullSymbol, t.TradeSize.ToString(System.Globalization.CultureInfo.InvariantCulture), t.TradePrice.ToString("F2", System.Globalization.CultureInfo.InvariantCulture), }; return string.Join(",", trade); }
private decimal CalculateIBCommissions(Trade t) { if (t.FullSymbol.Contains("STK")) { return (decimal)Math.Max(0.005 * Math.Abs(t.TradeSize), 1); } else if (t.FullSymbol.Contains("FUT")) { return 2.01m * Math.Abs(t.TradeSize); } else if (t.FullSymbol.Contains("OPT")) { return Math.Max(0.70m * Math.Abs(t.TradeSize), 1); } else if (t.FullSymbol.Contains("CASH")) { return Math.Max(0.000002m * (t.TradePrice * t.TradeSize), 2); } else { return 0; } }
private void OnGotFill(Trade t) { var handler = GotFillHandler; if (handler != null) handler(t); }
/// <summary> /// Executes any open orders allowed by the specified tick. /// </summary> /// <param name="tick">The tick.</param> /// <returns>the number of orders executed using the tick.</returns> public int Execute(Tick tick) { if (_pendingorders == 0) return 0; if (!tick.IsTrade && !_usebidaskfill) return 0; int filledorders = 0; Account[] accts = new Account[_masterorders.Count]; _masterorders.Keys.CopyTo(accts, 0); // go through each account for (int idx = 0; idx < accts.Length; idx++) { Account a = accts[idx]; // if account has requested no executions, skip it if (!a.Execute) continue; // make sure we have a record for this account if (!_mastertrades.ContainsKey(a.ID)) _mastertrades.Add(a.ID, new List<Trade>()); // track orders being removed and trades that need notification List<int> notifytrade = new List<int>(); List<int> remove = new List<int>(); // go through each order in the account for (int i = 0; i < _masterorders[a].Count; i++) { Order o = _masterorders[a][i]; //make sure tick is for the right stock if (tick.FullSymbol != o.FullSymbol) continue; bool filled = false; if (UseHighLiquidityFillsEOD) { Order oi = (Order)o; filled = oi.FillHighLiquidityEOD(tick, _usebidaskfill, false); } else if (o.TIF <= TimeInForce.GTC) { filled = o.Fill(tick, _usebidaskfill, false); // fill our trade } else if (o.TIF == TimeInForce.OPG) { // if it's already opened, we missed our shot if (_hasopened.Contains(o.FullSymbol)) continue; // otherwise make sure it's really the opening //if (tick.Exchange == OPGEX) { // it's the opening tick, so fill it as an opg filled = o.Fill(tick, _usebidaskfill, true); // mark this symbol as already being open _hasopened.Add(tick.FullSymbol); } } // other orders fill normally, except MOC orders which are at 4:00PM else if (o.TIF == TimeInForce.MOC) { if (tick.Time >= 160000) filled = o.Fill(tick, _usebidaskfill, false); // fill our trade } else filled = o.Fill(tick, _usebidaskfill, false); // fill our trade if (filled) { // get copy of trade for recording Trade trade = new Trade((Trade)o); // remove filled size from size available in trade if (_adjustincomingticksize) { if (_usebidaskfill) { if (o.Side) tick.AskSize -= trade.UnsignedSize; else tick.BidSize -= trade.UnsignedSize; } else tick.TradeSize -= trade.UnsignedSize; } // if trade represents entire requested order, mark order for removal if (trade.UnsignedSize == o.UnsignedSize) remove.Add(i); else // otherwise reflect order's remaining size o.OrderSize = (o.UnsignedSize - trade.UnsignedSize) * (o.OrderSide ? 1 : -1); // record trade _mastertrades[a.ID].Add(trade); // mark it for notification notifytrade.Add(_mastertrades[a.ID].Count - 1); // count the trade filledorders++; } } int rmcount = remove.Count; // remove the filled orders for (int i = remove.Count - 1; i >= 0; i--) _masterorders[a].RemoveAt(remove[i]); // unmark filled orders as pending _pendingorders -= rmcount; if (_pendingorders < 0) _pendingorders = 0; // notify subscribers of trade if (a.Notify) for (int tradeidx = 0; tradeidx < notifytrade.Count; tradeidx++) OnGotFill(_mastertrades[a.ID][notifytrade[tradeidx]]); } return filledorders; }
public Position(Trade t) { if (!t.IsValid) throw new Exception("Can't construct a position object from invalid trade."); _fullsymbol = t.FullSymbol; _avgprice = t.TradePrice; _size = t.TradeSize; _date = t.TradeDate; _time = t.TradeTime; _acct = t.Account; if (_size>0) _size *= t.Side ? 1 : -1; }
/// <summary> /// Called when orders are filled as trades. /// track or respond to trades here, eg: /// positionTracker.Adjust(fill); /// </summary> /// <param name="fill"></param> public virtual void GotFill(Trade f) { }
public void GotFill(Trade f) { if (f.Id == 0) { Debug(" fill id is empty: " + f.ToString()); return; } if (!IsTracked(f.Id)) { Debug(" fill id not tracked: " + f.Id); return; } // add to fills _fills[f.Id] += f.TradeSize; Debug(f.FullSymbol + " filled size: " + _fills[f.Id] + " ; on trade detail: " + f.ToString()); }
private void ClientGotOrderFilled(Trade k) { _tradelist.Add(k); System.Windows.Application.Current.Dispatcher.Invoke(() => { // order table int pos = OrderTable.Select(row => row.OrderId).ToList().IndexOf(k.Id); if (pos == -1) { OnDebug("Order id " + k.Id.ToString() + " is not found in order table; possibly new order."); } else { _ordertracker.GotFill(k); if (_ordertracker[k.Id] == 0) { OrderStatus status = OrderStatus.Filled; OrderTable[pos].Status = EnumDescConverter.GetEnumDescription(status); } else { OrderStatus status = OrderStatus.PartiallyFilled; _ordertable[pos].Status = EnumDescConverter.GetEnumDescription(status); } } // position table only handles one account // but it is guarantteed by order id _positiontracker.Adjust(k); pos = PositionTable.Select(row => row.Symbol).ToList().IndexOf(k.FullSymbol); if (pos == -1) { // add new position int count = PositionTable.Count; PositionTable.Add(new PositionEntry(count, k.FullSymbol, _positiontracker[k.FullSymbol].AvgPrice, _positiontracker[k.FullSymbol].Size, _positiontracker[k.FullSymbol].ClosedPL, _positiontracker[k.FullSymbol].OpenPL)); } else { // adjust position PositionTable[pos].AvgPrice = _positiontracker[k.FullSymbol].AvgPrice; PositionTable[pos].Size = _positiontracker[k.FullSymbol].Size; PositionTable[pos].ClosePL = _positiontracker[k.FullSymbol].ClosedPL; PositionTable[pos].OpenPL = _positiontracker[k.FullSymbol].OpenPL; } FillTable.Add(new FillEntry(k.Id, k.TradeTime, k.FullSymbol, k.TradeSize, k.TradePrice)); }); }
public static string ToChartLabel(Trade fill) { return (fill.TradeSize + fill.FullSymbol); }
/// <summary> /// this must be called once per position tracker, for each position update. /// if you are using your own position tracker with this trailing stop(eg from offset tracker, or somewhere else) /// you MUST call TrailTrackers Adjust and NOT call your position tracker's adjust /// </summary> /// <param name="fill"></param> public void Adjust(Trade fill) { // get index for symbol int idx = symidx(fill.FullSymbol); // only do following if we're tracking trail for this symbol if (idx != NOSYM) { // get current position size int psize = _pt[fill.FullSymbol].UnsignedSize; // get trailing information OffsetInfo trail = _trail[idx]; // get actual position size after change int asize = psize - fill.UnsignedSize; // if expected and actual match, mark pending as false if (esize[fill.FullSymbol] == asize) { D(fill.FullSymbol + " trailing stop completely filled with: " + fill.ToString()); _pendingfill[idx] = false; } else v(fill.FullSymbol + " trail partial fill: " + fill.ToString() + " e: " + esize[fill.FullSymbol] + " != a: " + asize); } else v(fill.FullSymbol + " fill: " + fill.ToString() + " ignored while trail disabled."); _pt.Adjust(fill); // if we're flat now, make sure ref price is reset if (_pt[fill.FullSymbol].isFlat) { _ref[idx] = 0; v(fill.FullSymbol + " flat, reset trail reference price."); } }
// Provides the executions which happened in the last 24 hours. // This event is fired when the reqExecutions() functions is invoked, or when an order is filled. public virtual void execDetails(int reqId, Contract contract, Execution execution) { Trade trade = new Trade(); //trade.Currency = contract.Currency; trade.Account = Account; trade.Id = 0; trade.TradePrice = (decimal)execution.Price; trade.TradeSize = (execution.Side == "BOT"?1:-1)*execution.Shares; // FullSymbol includes SecurityType, Exchange and Multiplier // trade.Security = (SecurityType)EnumDescConverter.GetEnumValue(typeof(SecurityType), contract.SecType); trade.FullSymbol = ContractToSecurityFullName(contract); // convert date and time DateTime dt = DateTime.ParseExact(execution.Time, "yyyyMMdd HH:mm:ss", CultureInfo.InvariantCulture); // Two blanks trade.TradeDate = dt.Year * 10000 + dt.Month * 100 + dt.Day; trade.TradeTime = dt.Hour * 10000 + dt.Minute * 100 + dt.Second; if (contract.SecType != "BAG") { if (_iborderIdToOrderInfo.ContainsKey(execution.OrderId)) { trade.Id = _iborderIdToOrderInfo[execution.OrderId].StrategyOrderId; if (_iborderIdToOrderInfo[execution.OrderId].IsAcknowledged) { OnGotFill(trade); return; } } // order not found or not acknowledged yet - defer fill notification _duplicateIBIdToDeferredTrade.Add(new KeyValuePair<int, Trade>(execution.OrderId, trade)); } }
private void ClientGotOrderFilled(Trade k) { foreach (StrategyItem si in _strategyitemlist) { si.S.GotFill(k); } }
void OnGotFill(Trade t) { if (GotFillDelegate != null) GotFillDelegate(t); }
public override void GotFill(Trade f) { if (_symbols.Contains(f.FullSymbol)) { _positiontracker.Adjust(f); //int idx = Array.IndexOf(_symbols, f.FullSymbol); int idx = _symbols.IndexOf(f.FullSymbol); _waittobefilled[idx] = false; _transactions++; if (_transactions >= _totaltransactions) { Shutdown(); } } }
void _broker_GotFill(Trade f) { if (_strategy != null) _strategy.GotFill(f); // tell others, e.g. FillTable GotFill(f); }
/// <summary> /// must send new fills here (eg call from Response.GotFill) /// </summary> /// <param name="t"></param> public void Adjust(Trade t) { // get original size int osize = _pt[t.symbol].Size; // update position _pt.Adjust(t); // see if it's our order OffsetInfo oi = GetOffset(t.symbol); // see what was hit bool hp = (t.id != 0) && (oi.ProfitId == t.id); bool hs = (t.id != 0) && (oi.StopId == t.id); // if we hit something if (hp || hs) { // notify debug(t.symbol + " hit " + (hp ? "profit" : "stop") + ": " + t.id); // see if we should clear offset if (hp && (oi.SentProfitSize == t.xsize)) { debug(t.symbol + " profit closed: " + t.id); oi.ProfitId = 0; } else if (hp) oi.SentProfitSize -= t.xsize; if (hs && (oi.SentStopSize == t.xsize)) { debug(t.symbol + " stop closed: " + t.id); oi.StopId = 0; } else if (hs) oi.SentStopSize -= t.xsize; if (HitOffset != null) HitOffset(t.symbol, t.id, t.xprice); } // if we're flat, nothing to do (or if we switched sides) Position p = _pt[t.symbol]; if (p.isFlat || (osize * p.Size < -1)) { if (p.isFlat) debug(t.symbol + " now flat."); else debug(t.symbol + " reversed: " + osize + " -> " + p.Size); CancelAll(t.symbol); // reset offset state but not configuration SetOffset(t.symbol, new OffsetInfo(this[t.symbol])); } else // save offset SetOffset(t.symbol, oi); // do we have events? if (!HasEvents()) return; // do update doupdate(t.symbol); }
void GotFill(Trade f) { if (GotFillEvent != null) GotFillEvent(f); }
void _client_GotFillDelegate(Trade obj) { _eventAggregator.GetEvent<OrderFillEvent>().Publish(obj); }
// these are for calculating closed pl // they do not adjust positions themselves /// <summary> /// Gets the closed PL on a per-share basis, ignoring how many shares are held. /// </summary> /// <param name="existing">The existing position.</param> /// <param name="closing">The portion of the position that's being closed/changed.</param> /// <returns></returns> public static decimal ClosePT(Position existing, Trade adjust) { if (!existing.isValid || !adjust.IsValid) throw new Exception("Invalid position provided. (existing:" + existing.ToString() + " adjustment:" + adjust.ToString()); if (existing.isFlat) return 0; // nothing to close if (existing.isLong == adjust.Side) return 0; // if we're adding, nothing to close return existing.isLong ? adjust.TradePrice - existing.AvgPrice : existing.AvgPrice - adjust.TradePrice; }