{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "ExecuteTime": {
     "end_time": "2018-08-15T00:41:02.434701Z",
     "start_time": "2018-08-15T00:41:01.840935Z"
    },
    "run_control": {
     "frozen": false,
     "read_only": false
    }
   },
   "outputs": [],
   "source": [
    "import math\n",
    "from pyqstrat.pq_utils import *\n",
    "\n",
    "class MarketOrder:\n",
    "    def __init__(self, symbol, date, qty, reason_code = ReasonCode.NONE, status = 'open'):\n",
    "        '''\n",
    "        Args:\n",
    "            symbol: A string\n",
    "            date: A numpy datetime indicating the time the order was placed\n",
    "            qty:  Number of contracts or shares.  Use a negative quantity for sell orders\n",
    "            reason_code: A string representing the reason this order was created.\n",
    "                Prefer a predefined constant from the ReasonCode class if it matches your reason for creating this order.\n",
    "            status: Status of the order, \"open\", \"filled\", etc. (default \"open\")\n",
    "        '''\n",
    "        self.symbol = symbol\n",
    "        self.date = date\n",
    "        if not np.isfinite(qty) or math.isclose(qty, 0): raise Exception(f'order qty must be finite and nonzero: {qty}')\n",
    "        self.qty = qty\n",
    "        self.reason_code = reason_code\n",
    "        self.status = status\n",
    "        \n",
    "    def __repr__(self):\n",
    "        return f'{self.symbol} {pd.Timestamp(self.date).to_pydatetime():%Y-%m-%d %H:%M} qty: {self.qty}' + (\n",
    "            '' if self.reason_code == ReasonCode.NONE else f' {self.reason_code}') + f' {self.status}'\n",
    "    \n",
    "    def params(self):\n",
    "        return {}\n",
    "        \n",
    "class LimitOrder:\n",
    "    def __init__(self, symbol, date, qty, limit_price, reason_code = ReasonCode.NONE, status = 'open'):\n",
    "        '''\n",
    "        Args:\n",
    "            symbol: A string\n",
    "            date: A numpy datetime indicating the time the order was placed\n",
    "            qty:  Number of contracts or shares.  Use a negative quantity for sell orders\n",
    "            limit_price: Limit price (float)\n",
    "            reason_code: A string representing the reason this order was created.\n",
    "                Prefer a predefined constant from the ReasonCode class if it matches your reason for creating this order.\n",
    "            status: Status of the order, \"open\", \"filled\", etc. (default \"open\")\n",
    "        '''\n",
    "        self.symbol = symbol\n",
    "        self.date = date\n",
    "        if not np.isfinite(qty) or math.isclose(qty, 0): raise Exception(f'order qty must be finite and nonzero: {qty}')\n",
    "        self.qty = qty\n",
    "        self.reason_code = reason_code\n",
    "        self.limit_price = limit_price\n",
    "        self.status = status\n",
    "        \n",
    "    def __repr__(self):\n",
    "        return f'{self.symbol} {pd.Timestamp(self.date).to_pydatetime():%Y-%m-%d %H:%M} qty: {self.qty} lmt_prc: {self.limit_price}' + (\n",
    "            '' if self.reason_code == ReasonCode.NONE else f' {self.reason_code}') + f' {self.status}'\n",
    "    \n",
    "    def params(self):\n",
    "        return {'limit_price' : self.limit_price}\n",
    "    \n",
    "class RollOrder:\n",
    "    '''A roll order is used to roll a future from one series to the next.  It represents a sell of one future and the buying of another future.'''\n",
    "    def __init__(self, symbol, date, close_qty, reopen_qty, reason_code = ReasonCode.ROLL_FUTURE, status = 'open'):\n",
    "        '''\n",
    "        Args:\n",
    "            symbol: A string\n",
    "            date: A numpy datetime indicating the time the order was placed\n",
    "            close_qty: Quantity of the future you are rolling\n",
    "            reopen_qty: Quantity of the future you are rolling to\n",
    "            reason_code: A string representing the reason this order was created.\n",
    "                Prefer a predefined constant from the ReasonCode class if it matches your reason for creating this order.\n",
    "            status: Status of the order, \"open\", \"filled\", etc. (default \"open\")\n",
    "        '''\n",
    "        self.symbol = symbol\n",
    "        self.date = date\n",
    "        if not np.isfinite(close_qty) or math.isclose(close_qty, 0) or not np.isfinite(reopen_qty) or math.isclose(reopen_qty, 0):\n",
    "            raise Exception(f'order quantities must be non-zero and finite: {close_qty} {reopen_qty}')\n",
    "        self.close_qty = close_qty\n",
    "        self.reopen_qty = reopen_qty\n",
    "        self.reason_code = reason_code\n",
    "        self.qty = close_qty # For display purposes when we print varying order types\n",
    "        self.status = status\n",
    "        \n",
    "    def params(self):\n",
    "        return {'close_qty' : self.close_qty, 'reopen_qty' : self.reopen_qty}\n",
    "        \n",
    "    def __repr__(self):\n",
    "        return f'{self.symbol} {pd.Timestamp(self.date).to_pydatetime():%Y-%m-%d %H:%M} close_qty: {self.close_qty} reopen_qty: {self.reopen_qty}' + (\n",
    "            '' if self.reason_code == ReasonCode.NONE else f' {self.reason_code}') + f' {self.status}'\n",
    "  \n",
    "class StopLimitOrder:\n",
    "    '''Used for stop loss or stop limit orders.  The order is triggered when price goes above or below trigger price, depending on whether this is a short\n",
    "      or long order.  Becomes either a market or limit order at that point, depending on whether you set the limit price or not.\n",
    "    '''\n",
    "    def __init__(self, symbol, date, qty, trigger_price, limit_price = np.nan, reason_code = ReasonCode.NONE, status = 'open'):\n",
    "        '''\n",
    "        Args:\n",
    "            symbol: A string\n",
    "            date: A numpy datetime indicating the time the order was placed\n",
    "            qty: Number of contracts or shares.  Use a negative value for sell orders\n",
    "            trigger_price: Order becomes a market or limit order if price crosses trigger_price.\n",
    "            limit_price: If not set (default), order becomes a market order when price crosses trigger price.  Otherwise it becomes a limit order\n",
    "            reason_code: A string representing the reason this order was created.\n",
    "                Prefer a predefined constant from the ReasonCode class if it matches your reason for creating this order.\n",
    "            status: Status of the order, \"open\", \"filled\", etc. (default \"open\")\n",
    "        '''      \n",
    "        self.symbol = symbol\n",
    "        self.date = date\n",
    "        if not np.isfinite(qty) or math.isclose(qty, 0): raise Exception(f'order qty must be finite and nonzero: {qty}')\n",
    "        self.qty = qty\n",
    "        self.trigger_price = trigger_price\n",
    "        self.limit_price = limit_price\n",
    "        self.reason_code = reason_code\n",
    "        self.triggered = False\n",
    "        self.status =  status\n",
    "        \n",
    "    def params(self):\n",
    "        return {'trigger_price' : self.trigger_price, 'limit_price' : self.limit_price}\n",
    "        \n",
    "    def __repr__(self):\n",
    "        return f'{self.symbol} {pd.Timestamp(self.date).to_pydatetime():%Y-%m-%d %H:%M} qty: {self.qty} trigger_prc: {self.trigger_price} limit_prc: {self.limit_price}' + (\n",
    "            '' if self.reason_code == ReasonCode.NONE else f' {self.reason_code}') + f' {self.status}'\n",
    "                "
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.6"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
