# Path: alephnull/finance/slippage.py
# class VolumeShareSlippage(SlippageModel):
#     def __init__(self,
#                  volume_limit=.25,
#                  price_impact=0.1):
# 
#         self.volume_limit = volume_limit
#         self.price_impact = price_impact
# 
#     def __repr__(self):
#         return """
# {class_name}(
#     volume_limit={volume_limit},
#     price_impact={price_impact})
# """.strip().format(class_name=self.__class__.__name__,
#                    volume_limit=self.volume_limit,
#                    price_impact=self.price_impact)
# 
#     def process_order(self, event, order):
# 
#         max_volume = self.volume_limit * event.volume
# 
#         # price impact accounts for the total volume of transactions
#         # created against the current minute bar
#         remaining_volume = max_volume - self.volume_for_bar
#         if remaining_volume < 1:
#             # we can't fill any more transactions
#             return
# 
#         # the current order amount will be the min of the
#         # volume available in the bar or the open amount.
#         cur_volume = int(min(remaining_volume, abs(order.open_amount)))
# 
#         if cur_volume < 1:
#             return
# 
#         # tally the current amount into our total amount ordered.
#         # total amount will be used to calculate price impact
#         total_volume = self.volume_for_bar + cur_volume
# 
#         volume_share = min(total_volume / event.volume,
#                            self.volume_limit)
# 
#         simulated_impact = (volume_share) ** 2 \
#                            * math.copysign(self.price_impact, order.direction) \
#                            * event.price
# 
#         return create_transaction(
#             event,
#             order,
#             # In the future, we may want to change the next line
#             # for limit pricing
#             event.price + simulated_impact,
#             math.copysign(cur_volume, order.direction)
#         )
# 
# def transact_partial(slippage, commission):
#     return partial(transact_stub, slippage, commission)
# 
# def check_order_triggers(order, event):
#     """
#     Given an order and a trade event, return a tuple of
#     (stop_reached, limit_reached).
#     For market orders, will return (False, False).
#     For stop orders, limit_reached will always be False.
#     For limit orders, stop_reached will always be False.
# 
#     Orders that have been triggered already (price targets reached),
#     the order's current values are returned.
#     """
#     if order.triggered:
#         return (order.stop_reached, order.limit_reached)
# 
#     stop_reached = False
#     limit_reached = False
#     # if the stop price is reached, simply set stop_reached
#     if order.stop is not None:
#         if (order.direction * (event.price - order.stop) <= 0):
#             # convert stop -> limit or market
#             stop_reached = True
# 
#     # if the limit price is reached, we execute this order at
#     # (event.price + simulated_impact)
#     # we skip this order with a continue when the limit is not reached
#     if order.limit is not None:
#         # if limit conditions not met, then continue
#         if (order.direction * (event.price - order.limit) <= 0):
#             limit_reached = True
# 
#     return (stop_reached, limit_reached)


import math
import uuid
import numpy as np
import alephnull.errors
import alephnull.protocol as zp
import alephnull.utils.math_utils as zp_math
from copy import copy
from collections import defaultdict
from logbook import Logger
from alephnull.finance.slippage import (
    VolumeShareSlippage,
    transact_partial,
    check_order_triggers
    )
from alephnull.finance.commission import PerShare
from alephnull.utils.protocol_utils import Enum
def round_for_minimum_price_variation(x, is_buy, diff=(0.0095 - .005)):
    # relies on rounding half away from zero, unlike numpy's bankers' rounding
    rounded = round(x - (diff if is_buy else -diff), 2)
    if zp_math.tolerant_equals(rounded, 0.0):
        return 0.0
    return rounded


class Blotter(object):
    def __init__(self):
        self.transact = transact_partial(VolumeShareSlippage(), PerShare())
        # these orders are aggregated by sid
        self.open_orders = defaultdict(list)
        # keep a dict of orders by their own id
        self.orders = {}
        # holding orders that have come in since the last
        # event.
        self.new_orders = []
        self.current_dt = None
        self.max_shares = int(1e+11)

    def __repr__(self):
        return """
{class_name}(
    transact_partial={transact_partial},
    open_orders={open_orders},
    orders={orders},
    new_orders={new_orders},
    current_dt={current_dt})
""".strip().format(class_name=self.__class__.__name__,

# Path: alephnull/finance/slippage.py
# class VolumeShareSlippage(SlippageModel):
#     def __init__(self,
#                  volume_limit=.25,
#                  price_impact=0.1):
# 
#         self.volume_limit = volume_limit
#         self.price_impact = price_impact
# 
#     def __repr__(self):
#         return """
# {class_name}(
#     volume_limit={volume_limit},
#     price_impact={price_impact})
# """.strip().format(class_name=self.__class__.__name__,
#                    volume_limit=self.volume_limit,
#                    price_impact=self.price_impact)
# 
#     def process_order(self, event, order):
# 
#         max_volume = self.volume_limit * event.volume
# 
#         # price impact accounts for the total volume of transactions
#         # created against the current minute bar
#         remaining_volume = max_volume - self.volume_for_bar
#         if remaining_volume < 1:
#             # we can't fill any more transactions
#             return
# 
#         # the current order amount will be the min of the
#         # volume available in the bar or the open amount.
#         cur_volume = int(min(remaining_volume, abs(order.open_amount)))
# 
#         if cur_volume < 1:
#             return
# 
#         # tally the current amount into our total amount ordered.
#         # total amount will be used to calculate price impact
#         total_volume = self.volume_for_bar + cur_volume
# 
#         volume_share = min(total_volume / event.volume,
#                            self.volume_limit)
# 
#         simulated_impact = (volume_share) ** 2 \
#                            * math.copysign(self.price_impact, order.direction) \
#                            * event.price
# 
#         return create_transaction(
#             event,
#             order,
#             # In the future, we may want to change the next line
#             # for limit pricing
#             event.price + simulated_impact,
#             math.copysign(cur_volume, order.direction)
#         )
# 
# def transact_partial(slippage, commission):
#     return partial(transact_stub, slippage, commission)
# 
# def check_order_triggers(order, event):
#     """
#     Given an order and a trade event, return a tuple of
#     (stop_reached, limit_reached).
#     For market orders, will return (False, False).
#     For stop orders, limit_reached will always be False.
#     For limit orders, stop_reached will always be False.
# 
#     Orders that have been triggered already (price targets reached),
#     the order's current values are returned.
#     """
#     if order.triggered:
#         return (order.stop_reached, order.limit_reached)
# 
#     stop_reached = False
#     limit_reached = False
#     # if the stop price is reached, simply set stop_reached
#     if order.stop is not None:
#         if (order.direction * (event.price - order.stop) <= 0):
#             # convert stop -> limit or market
#             stop_reached = True
# 
#     # if the limit price is reached, we execute this order at
#     # (event.price + simulated_impact)
#     # we skip this order with a continue when the limit is not reached
#     if order.limit is not None:
#         # if limit conditions not met, then continue
#         if (order.direction * (event.price - order.limit) <= 0):
#             limit_reached = True
# 
#     return (stop_reached, limit_reached)


# Path: alephnull/finance/blotter.py
import math
import uuid
import numpy as np
import alephnull.errors
import alephnull.protocol as zp
import alephnull.utils.math_utils as zp_math
from copy import copy
from collections import defaultdict
from logbook import Logger
from alephnull.finance.slippage import (
    VolumeShareSlippage,
    transact_partial,
    check_order_triggers
    )
from alephnull.finance.commission import PerShare
from alephnull.utils.protocol_utils import Enum

def round_for_minimum_price_variation(x, is_buy, diff=(0.0095 - .005)):
    # relies on rounding half away from zero, unlike numpy's bankers' rounding
    rounded = round(x - (diff if is_buy else -diff), 2)
    if zp_math.tolerant_equals(rounded, 0.0):
        return 0.0
    return rounded


class Blotter(object):
    def __init__(self):
        self.transact = transact_partial(VolumeShareSlippage(), PerShare())
        # these orders are aggregated by sid
        self.open_orders = defaultdict(list)
        # keep a dict of orders by their own id
        self.orders = {}
        # holding orders that have come in since the last
        # event.
        self.new_orders = []
        self.current_dt = None
        self.max_shares = int(1e+11)

    def __repr__(self):
        return """
{class_name}(
    transact_partial={transact_partial},
    open_orders={open_orders},
    orders={orders},
    new_orders={new_orders},
    current_dt={current_dt})
""".strip().format(class_name=self.__class__.__name__,

                   transact_partial=self.transact.args,