tradingmachine.orders.plan_parts.from_fill_pricing
¶
The from_fill pricing rule of a plan: an exit placed a distance from the price its position was opened at.
UBI prices the exit from the average fill of the orders that opened the position, in the direction that suits the side it is sent on, so one setting suits a position opened either way. When both sides of a two-sided entry filled, only the fills on the side the position is held on count, so a short opened at 990 and partly bought back at 1010 keeps its exits measured from 990. With stop_distance the exit is a native stop-limit that far beyond the fill against the position, with its limit stop_limit_offset further on; with target_distance it is a limit that far beyond the fill in the position's favour. Give the stop pair or the target, not both. Prices are rounded to the tick, and nothing is sent until the opening order has filled. The order must sit under a ThenPart's each_fill or on_complete child, or UBI refuses the plan with from_fill_needs_then.
Typical usage example:
pricing = from_fill_pricing.FromFillPricing( stop_distance=10.0, stop_limit_offset=1.0, ) document = pricing.document()
FromFillPricing
¶
Bases: PlanPart
A pricing rule for an exit set a distance from the fill that opened its position.
Attributes:
| Name | Type | Description |
|---|---|---|
stop_distance |
The float distance in rupees from the fill to the stop's trigger, or None for a target. |
|
stop_limit_offset |
The float distance in rupees past the stop's trigger to its limit, or None for a target. |
|
target_distance |
The float distance in rupees from the fill to the target's limit, or None for a stop. |
Initialises the rule as a stop or as a target.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
stop_distance
|
float | None
|
The float distance in rupees from the fill to the stop's trigger, given with |
None
|
stop_limit_offset
|
float | None
|
The float distance in rupees past the stop's trigger to its limit, given with |
None
|
target_distance
|
float | None
|
The float distance in rupees from the fill to the target's limit, or None for a stop. |
None
|
Source code in src/tradingmachine/orders/plan_parts/from_fill_pricing.py
document
¶
Builds the from_fill pricing object UBI reads, holding every setting that is not None.
Returns:
| Type | Description |
|---|---|
dict
|
A dict with the single key |
Examples:
Print a stop ten rupees from the fill with its limit one rupee past the trigger:
from tradingmachine.orders.plan_parts import from_fill_pricing
pricing = from_fill_pricing.FromFillPricing(
stop_distance=10.0,
stop_limit_offset=1.0,
)
print(pricing.document())
Print an entry followed by a stop and a target measured from its fill, which share the position so a fill on one reduces the other:
from tradingmachine.orders.plan_parts import either_part
from tradingmachine.orders.plan_parts import from_fill_pricing
from tradingmachine.orders.plan_parts import order_part
from tradingmachine.orders.plan_parts import then_part
part = then_part.ThenPart(
first=order_part.OrderPart(),
each_fill=either_part.EitherPart(
children=[
order_part.OrderPart(
side="protect",
pricing=from_fill_pricing.FromFillPricing(
stop_distance=10.0,
stop_limit_offset=1.0,
),
),
order_part.OrderPart(
side="protect",
pricing=from_fill_pricing.FromFillPricing(
target_distance=20.0,
),
),
],
sibling_rule="reduce",
),
)
print(part.document())
Source code in src/tradingmachine/orders/plan_parts/from_fill_pricing.py
Example programs¶
Build a dip entry followed by a stop and a target measured from wherever the entry fills¶
Run it with .venv/bin/python examples/orders/plan_parts/from_fill_pricing/from_fill_pricing/stop_and_target_after_a_dip_entry.py.
"""Build a dip entry followed by a stop and a target measured from wherever the entry fills.
The program reads Vodafone Idea's last price and builds a Then join: a buy that waits for the price to fall 1%, and on each of its fills an Either join of a stop 2% of the price below the fill and a target 4% above it, which share the position so a fill on one reduces the other. The exits need no absolute prices, because UBI measures them from the entry's average fill. It prints the join's object as UBI would read it. Nothing is sent to UBI's order routes.
Typical usage example:
.venv/bin/python examples/orders/plan_parts/from_fill_pricing/from_fill_pricing/stop_and_target_after_a_dip_entry.py
"""
import json
from tradingmachine.assets import equities
from tradingmachine.orders.plan_parts import either_part
from tradingmachine.orders.plan_parts import from_fill_pricing
from tradingmachine.orders.plan_parts import order_part
from tradingmachine.orders.plan_parts import price_crosses
from tradingmachine.orders.plan_parts import then_part
class DipEntryWithExits:
"""A dip buy of Vodafone Idea with a stop and a target measured from its fill.
Attributes:
share: The tradingmachine.assets.equities.Equity for Vodafone Idea on the NSE.
"""
def __init__(self):
"""Looks up the share.
Raises:
tradingmachine.assets.exceptions.InstrumentError: The share could not be found in UBI.
"""
self.share = equities.Equity(exchange="nse", symbol="IDEA")
def run(self) -> None:
"""Prints the join's object.
Returns:
None.
Raises:
ValueError: UBI has no last price for the share.
"""
last_price = self.share.last_price
if last_price is None:
raise ValueError(f"UBI has no last price for {self.share!r}")
tick_size = 0.05
if self.share.tick_size is not None:
tick_size = float(self.share.tick_size)
stop = order_part.OrderPart(
side="protect",
pricing=from_fill_pricing.FromFillPricing(
stop_distance=round(last_price * 0.02, 2),
stop_limit_offset=tick_size,
),
)
target = order_part.OrderPart(
side="protect",
pricing=from_fill_pricing.FromFillPricing(
target_distance=round(last_price * 0.04, 2),
),
)
part = then_part.ThenPart(
first=order_part.OrderPart(
trigger=price_crosses.PriceCrosses(
level=round(last_price * 0.99, 2),
),
),
each_fill=either_part.EitherPart(
children=[
stop,
target,
],
sibling_rule="reduce",
),
)
print(f"Last price of {self.share.symbol}: {last_price}")
print(json.dumps(part.document(), indent=2))
if __name__ == "__main__":
DipEntryWithExits().run()
Build an entry whose single target is sent only once the whole entry has filled, measured from its average fill¶
Run it with .venv/bin/python examples/orders/plan_parts/from_fill_pricing/from_fill_pricing/target_once_the_entry_completes.py.
"""Build an entry whose single target is sent only once the whole entry has filled, measured from its average fill.
The program builds a Then join for Vodafone Idea with `on_complete`, so the target waits until the buy is done, and prices the target half a rupee above the entry's average fill. The same exit works unchanged after a sale, where UBI places it below the fill instead. It prints the join's object as UBI would read it. Nothing is sent to UBI's order routes.
Typical usage example:
.venv/bin/python examples/orders/plan_parts/from_fill_pricing/from_fill_pricing/target_once_the_entry_completes.py
"""
import json
from tradingmachine.assets import equities
from tradingmachine.orders.plan_parts import from_fill_pricing
from tradingmachine.orders.plan_parts import order_part
from tradingmachine.orders.plan_parts import then_part
class TargetAfterCompletion:
"""A buy of Vodafone Idea followed by a target once it has filled completely.
Attributes:
share: The tradingmachine.assets.equities.Equity for Vodafone Idea on the NSE.
"""
def __init__(self):
"""Looks up the share.
Raises:
tradingmachine.assets.exceptions.InstrumentError: The share could not be found in UBI.
"""
self.share = equities.Equity(exchange="nse", symbol="IDEA")
def run(self) -> None:
"""Prints the join's object.
Returns:
None.
Raises:
Nothing.
"""
part = then_part.ThenPart(
first=order_part.OrderPart(
instrument=self.share,
transaction_type="buy",
quantity=10,
),
on_complete=order_part.OrderPart(
side="protect",
pricing=from_fill_pricing.FromFillPricing(target_distance=0.5),
),
)
print(f"Buy of {self.share.symbol} with a target half a rupee up:")
print(json.dumps(part.document(), indent=2))
if __name__ == "__main__":
TargetAfterCompletion().run()