Skip to content

Commit

Permalink
Merge pull request #98 from ChocoShell/order-builder
Browse files Browse the repository at this point in the history
Add Place Order models and validation
  • Loading branch information
timkpaine authored Jun 17, 2020
2 parents 9410d18 + 6ab4d6d commit e96be0e
Show file tree
Hide file tree
Showing 17 changed files with 1,010 additions and 0 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,9 @@ ENV/
# Rope project settings
.ropeproject

# VS Code project settings
.vscode

# mkdocs documentation
/site

Expand Down
14 changes: 14 additions & 0 deletions tdameritrade/orders/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
"""Orders Submodule
This module is used to construct valid json for the place orders endpoint.
https://developer.tdameritrade.com/account-access/apis/post/accounts/%7BaccountId%7D/orders-0
The validation is done by the orders.models.base.BaseOrder class
The order_builder file incudes sample order builder functions created from
https://developer.tdameritrade.com/content/place-order-samples
"""

from . import order_builder

__all__ = ["order_builder"]
258 changes: 258 additions & 0 deletions tdameritrade/orders/constants.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,258 @@
"""Constants used in Orders
"""
from enum import Enum


class ExtendedConstant(str, Enum):
"""
Base Enum class used by all order Enums.
"""

@classmethod
def list(cls):
"""Lists all values in Enum
Found here: https://stackoverflow.com/questions/29503339/how-to-get-all-values-from-python-enum-class/54919285#54919285
"""
return list(map(lambda c: c.value, cls))


class Session(ExtendedConstant):
NORMAL = "NORMAL"
AM = "AM"
PM = "PM"
SEAMLESS = "SEAMLESS"


class Duration(ExtendedConstant):
DAY = "DAY"
GOOD_TILL_CANCEL = "GOOD_TILL_CANCEL"
FILL_OR_KILL = "FILL_OR_KILL"


class OrderType(ExtendedConstant):
MARKET = "MARKET"
LIMIT = "LIMIT"
STOP = "STOP"
STOP_LIMIT = "STOP_LIMIT"
TRAILING_STOP = "TRAILING_STOP"
MARKET_ON_CLOSE = "MARKET_ON_CLOSE"
EXERCISE = "EXERCISE"
TRAILING_STOP_LIMIT = "TRAILING_STOP_LIMIT"
NET_DEBIT = "NET_DEBIT"
NET_CREDIT = "NET_CREDIT"
NET_ZERO = "NET_ZERO"


class ComplexOrderStrategyType(ExtendedConstant):
NONE = "NONE"
COVERED = "COVERED"
VERTICAL = "VERTICAL"
BACK_RATIO = "BACK_RATIO"
CALENDAR = "CALENDAR"
DIAGONAL = "DIAGONAL"
STRADDLE = "STRADDLE"
STRANGLE = "STRANGLE"
COLLAR_SYNTHETIC = "COLLAR_SYNTHETIC"
BUTTERFLY = "BUTTERFLY"
CONDOR = "CONDOR"
IRON_CONDOR = "IRON_CONDOR"
VERTICAL_ROLL = "VERTICAL_ROLL"
COLLAR_WITH_STOCK = "COLLAR_WITH_STOCK"
DOUBLE_DIAGONAL = "DOUBLE_DIAGONAL"
UNBALANCED_BUTTERFLY = "UNBALANCED_BUTTERFLY"
UNBALANCED_CONDOR = "UNBALANCED_CONDOR"
UNBALANCED_IRON_CONDOR = "UNBALANCED_IRON_CONDOR"
UNBALANCED_VERTICAL_ROLL = "UNBALANCED_VERTICAL_ROLL"
CUSTOM = "CUSTOM"


class RequestedDestination(ExtendedConstant):
INET = "INET"
ECN_ARCA = "ECN_ARCA"
CBOE = "CBOE"
AMEX = "AMEX"
PHLX = "PHLX"
ISE = "ISE"
BOX = "BOX"
NYSE = "NYSE"
NASDAQ = "NASDAQ"
BATS = "BATS"
C2 = "C2"
AUTO = "AUTO"


class StopPriceLinkBasis(ExtendedConstant):
MANUAL = "MANUAL"
BASE = "BASE"
TRIGGER = "TRIGGER"
LAST = "LAST"
BID = "BID"
ASK = "ASK"
ASK_BID = "ASK_BID"
MARK = "MARK"
AVERAGE = "AVERAGE"


class StopPriceLinkType(ExtendedConstant):
VALUE = "VALUE"
PERCENT = "PERCENT"
TICK = "TICK"


class StopType(ExtendedConstant):
STANDARD = "STANDARD"
BID = "BID"
ASK = "ASK"
LAST = "LAST"
MARK = "MARK"


class PriceLinkBasis(ExtendedConstant):
MANUAL = "MANUAL"
BASE = "BASE"
TRIGGER = "TRIGGER"
LAST = "LAST"
BID = "BID"
ASK = "ASK"
ASK_BID = "ASK_BID"
MARK = "MARK"
AVERAGE = "AVERAGE"


class PriceLinkType(ExtendedConstant):
VALUE = "VALUE"
PERCENT = "PERCENT"
TICK = "TICK"


class TaxLotMethod(ExtendedConstant):
FIFO = "FIFO"
LIFO = "LIFO"
HIGH_COST = "HIGH_COST"
LOW_COST = "LOW_COST"
AVERAGE_COST = "AVERAGE_COST"
SPECIFIC_LOT = "SPECIFIC_LOT"


class SpecialInstruction(ExtendedConstant):
ALL_OR_NONE = "ALL_OR_NONE"
DO_NOT_REDUCE = "DO_NOT_REDUCE"
ALL_OR_NONE_DO_NOT_REDUCE = "ALL_OR_NONE_DO_NOT_REDUCE"


class OrderStrategyType(ExtendedConstant):
SINGLE = "SINGLE"
OCO = "OCO"
TRIGGER = "TRIGGER"


class Status(ExtendedConstant):
AWAITING_PARENT_ORDER = "AWAITING_PARENT_ORDER"
AWAITING_CONDITION = "AWAITING_CONDITION"
AWAITING_MANUAL_REVIEW = "AWAITING_MANUAL_REVIEW"
ACCEPTED = "ACCEPTED"
AWAITING_UR_OUT = "AWAITING_UR_OUT"
PENDING_ACTIVATION = "PENDING_ACTIVATION"
QUEUED = "QUEUED"
WORKING = "WORKING"
REJECTED = "REJECTED"
PENDING_CANCEL = "PENDING_CANCEL"
CANCELED = "CANCELED"
PENDING_REPLACE = "PENDING_REPLACE"
REPLACED = "REPLACED"
FILLED = "FILLED"
EXPIRED = "EXPIRED"


# Order Leg Constants


class OrderLegType(ExtendedConstant):
EQUITY = "EQUITY"
OPTION = "OPTION"
INDEX = "INDEX"
MUTUAL_FUND = "MUTUAL_FUND"
CASH_EQUIVALENT = "CASH_EQUIVALENT"
FIXED_INCOME = "FIXED_INCOME"
CURRENCY = "CURRENCY"


class Instruction(ExtendedConstant):
BUY = "BUY"
SELL = "SELL"
BUY_TO_COVER = "BUY_TO_COVER"
SELL_SHORT = "SELL_SHORT"
BUY_TO_OPEN = "BUY_TO_OPEN"
BUY_TO_CLOSE = "BUY_TO_CLOSE"
SELL_TO_OPEN = "SELL_TO_OPEN"
SELL_TO_CLOSE = "SELL_TO_CLOSE"
EXCHANGE = "EXCHANGE"


class PositionEffect(ExtendedConstant):
OPENING = "OPENING"
CLOSING = "CLOSING"
AUTOMATIC = "AUTOMATIC"


class QuantityType(ExtendedConstant):
ALL_SHARES = "ALL_SHARES"
DOLLARS = "DOLLARS"
SHARES = "SHARES"


# Activity Enums


class ActivityType(ExtendedConstant):
EXECUTION = "EXECUTION"
ORDER_ACTION = "ORDER_ACTION"


class ExecutionType(ExtendedConstant):
FILL = "FILL"


# Instrument Enums


class InstrumentAssetType(ExtendedConstant):
EQUITY = "EQUITY"
OPTION = "OPTION"
INDEX = "INDEX"
MUTUAL_FUND = "MUTUAL_FUND"
CASH_EQUIVALENT = "CASH_EQUIVALENT"
FIXED_INCOME = "FIXED_INCOME"
CURRENCY = "CURRENCY"


class MutualFundType(ExtendedConstant):
NOT_APPLICABLE = "NOT_APPLICABLE"
OPEN_END_NON_TAXABLE = "OPEN_END_NON_TAXABLE"
OPEN_END_TAXABLE = "OPEN_END_TAXABLE"
NO_LOAD_NON_TAXABLE = "NO_LOAD_NON_TAXABLE"
NO_LOAD_TAXABLE = "NO_LOAD_TAXABLE"


class CashEquivalentType(ExtendedConstant):
SAVINGS = "SAVINGS"
MONEY_MARKET_FUND = "MONEY_MARKET_FUND"


class OptionType(ExtendedConstant):
VANILLA = "VANILLA"
BINARY = "BINARY"
BARRIER = "BARRIER"


class OptionPutCall(ExtendedConstant):
PUT = "PUT"
CALL = "CALL"


class OptionDeliverableCurrencyType(ExtendedConstant):
USD = "USD"
CAD = "CAD"
EUR = "EUR"
JPY = "JPY"
48 changes: 48 additions & 0 deletions tdameritrade/orders/leg_builder.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
from .constants import Instruction, InstrumentAssetType
from .models.instruments import EquityInstrument, OptionInstrument
from .models.leg import OrderLeg


def create_equity_order_leg(
instruction, quantity, symbol, description=None, cusip=None, **order_leg_kwargs,
):
"""Creates OrderLeg for equity orders
"""
valid_instructions = [
Instruction("BUY"),
Instruction("SELL"),
Instruction("BUY_TO_COVER"),
Instruction("SELL_SHORT"),
]

asset_type = InstrumentAssetType.EQUITY

if instruction not in valid_instructions:
raise Exception(
f"{instruction} not in valid instruction list for Equity Order Leg"
)

instrument = EquityInstrument(symbol=symbol, assetType=asset_type)
return OrderLeg(
instruction=instruction,
quantity=quantity,
instrument=instrument,
**order_leg_kwargs,
)


def create_option_order_leg(
instruction, quantity, symbol, description=None, cusip=None, **order_leg_kwargs,
):
"""Creates Option OrderLeg
"""
asset_type = InstrumentAssetType.OPTION

instrument = OptionInstrument(symbol=symbol, assetType=asset_type)

return OrderLeg(
instruction=instruction,
quantity=quantity,
instrument=instrument,
**order_leg_kwargs,
)
8 changes: 8 additions & 0 deletions tdameritrade/orders/models/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
from . import activities, instruments, leg, orders

__all__ = [
"activities",
"instruments",
"leg",
"orders",
]
34 changes: 34 additions & 0 deletions tdameritrade/orders/models/activities.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
from dataclasses import dataclass
from typing import List

from ..constants import ActivityType, ExecutionType
from .base import BaseOrder


@dataclass
class OrderActivity(BaseOrder):
pass


@dataclass(frozen=True)
class ExecutionLeg(BaseOrder):
"""ExecutionLeg used in Execution
"""

legId: int = None
quantity: int = None
mismarkedQuantity: int = None
price: int = None
time: str = None


@dataclass(frozen=True)
class Execution(OrderActivity):
"""Execution
"""

activityType: ActivityType = None
executionType: ExecutionType = None
quantity: int = None
orderRemainingQuantity: int = None
executionLegs: List = None # List[ExecutionLeg]. Issue with List[type] formatting
Loading

0 comments on commit e96be0e

Please sign in to comment.