/// <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 only need to adjust it once, so if you adjust it directly you don't need to call again here. /// </summary> /// <param name="fill"></param> public void Adjust(Trade fill) { // get index for symbol int idx = symidx(fill.symbol); // only do following if we're tracking trail for this symbol if (idx != NOSYM) { // get current position size int psize = _pt[fill.symbol].UnsignedSize; // get trailing information OffsetInfo trail = _trail[idx]; // get expected position size int esize = psize - Calc.Norm2Min(psize * trail.StopPercent, trail.MinimumLotSize); // get actual position size after change int asize = psize - fill.UnsignedSize; // if expected and actual match, mark pending as false if (esize == asize) { D("filled trailing stop for: " + fill.symbol); _pendingfill[idx] = false; } } _pt.Adjust(fill); // if we're flat now, make sure ref price is reset if (_pt[fill.symbol].isFlat) { _ref[idx] = 0; } }
/// <summary> /// track and correct oversells (either by splitting into two orders, or dropping oversell) /// </summary> /// <param name="o"></param> public void sendorder(Order o) { // get original size int osize = o.size; int uosize = o.UnsignedSize; // get existing size int size = _pt[o.symbol].Size; int upsize = _pt[o.symbol].UnsignedSize; // check for overfill/overbuy bool over = (o.size * size < -1) && (o.UnsignedSize > Math.Abs(size)) && (upsize >= MinLotSize); // detect if (over) { // determine correct size int oksize = _pt[o.symbol].FlatSize; // adjust o.size = Calc.Norm2Min(oksize, MinLotSize); // send sonow(o); // count osa++; // notify debug(o.symbol + " oversell detected on pos: " + size + " order adjustment: " + osize + "->" + size + " " + o.ToString()); // see if we're splitting if (Split) { // calculate new size int nsize = Calc.Norm2Min(Math.Abs(uosize - Math.Abs(oksize)), MinLotSize); // adjust side nsize *= (o.side ? 1 : -1); // create order Order newo = new OrderImpl(o); newo.size = nsize; newo.id = _idt.AssignId; if (_orgid2splitid.ContainsKey(o.id)) { _orgid2splitid[o.id] = newo.id; } else { _orgid2splitid.Add(o.id, newo.id); } // send if (nsize != 0) { sonow(newo); } // notify debug(o.symbol + " splitting oversell/overcover: " + o.ToString() + " to 2nd order: " + newo); } } else { sonow(o); } }
/// <summary> /// flat specified % of a position. /// if the position is an odd-lot, optionally normalize to a standard lot size (if normalizeSize = true) /// if normalizing, specify lot size /// </summary> /// <param name="current"></param> /// <param name="percent"></param> /// <param name="normalizeSize"></param> /// <param name="MinimumLotSize"></param> public MarketOrderFlat(Position current, decimal percent, bool normalizeSize, int MinimumLotSize) : base(current.Symbol, normalizeSize ? Calc.Norm2Min((decimal)percent * current.FlatSize, MinimumLotSize) : (int)(percent * current.FlatSize)) { }