A class to generate, save and load unique transaction reference numbers for an application

The name of the pictureThe name of the pictureThe name of the pictureClash Royale CLAN TAG#URR8PPP





.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty margin-bottom:0;







up vote
7
down vote

favorite












This code is a class I use in my financial market trading bot (note: I'm a daytrader-come-beginner programmer, not the other way around).



Although I have the application running successfully, it has major design flaws which I intend to now address ASAP.



An API requires that a unique transaction ref is submitted with each new order, otherwise, that order will be rejected. I have very little idea if this is a competent or robust design, I could not find any guidance on the issue elsewhere.



I'm very much open to refactoring or a completely new design.



class UniqueTransactionRef:
"""Transaction reference number iterator

Loads, generates and saves unique transaction ref data for ``Bot`` orders

:ivar file: absolute path the the .json transaction ref data file
:ivar num: an integer representing the last generated transaction ref number
"""

default_file = r"C:BotBottrans_ref.json"

def __init__(self, file=None):
"""Initialize the UniqueTransactionRef object

:param file: an absolute path to a .json file containing the transaction
reference number, as an integer
"""
self.file = file if file else self.default_file
self.num = 0
self.load()

def __iter__(self):
return self

def __next__(self):
"""Increment the self.num attribute. Save the value to the local file.

:returns: a string formatted version of the self.num class attribute
"""
self.num += 1
self.save()
return str(self.num)

def get(self):
"""Call the ``next`` function on self """
return next(self)

def load(self):
"""Load the transaction ref data from the local file

:raises errors.UniqueTransactionRefError: Cannot find file
"""
try:
with open(self.file) as f:
self.num = json.load(f)
except FileNotFoundError:
raise errors.UniqueTransactionRefError(
self.file,
num=self.num,
message="Cannot find file",
)

def save(self):
"""Save self.num to the designated local file

:raises UniqueTransactionRefError:
"""
try:
with open(self.file, "w") as f:
json.dump(self.num, f)
except Exception as e:
raise errors.UniqueTransactionRefError(self.file,
num=self.num,
message=e)
unique_trans_ref = UniqueTransactionRef() # module level variable


Simplified example usage:



class Bot:
def __init__(self, unique_trans_ref):
self.unique_trans_ref = unique_trans_ref

def construct_order():
trans_ref = next(self.unique_trans_ref)






share|improve this question



























    up vote
    7
    down vote

    favorite












    This code is a class I use in my financial market trading bot (note: I'm a daytrader-come-beginner programmer, not the other way around).



    Although I have the application running successfully, it has major design flaws which I intend to now address ASAP.



    An API requires that a unique transaction ref is submitted with each new order, otherwise, that order will be rejected. I have very little idea if this is a competent or robust design, I could not find any guidance on the issue elsewhere.



    I'm very much open to refactoring or a completely new design.



    class UniqueTransactionRef:
    """Transaction reference number iterator

    Loads, generates and saves unique transaction ref data for ``Bot`` orders

    :ivar file: absolute path the the .json transaction ref data file
    :ivar num: an integer representing the last generated transaction ref number
    """

    default_file = r"C:BotBottrans_ref.json"

    def __init__(self, file=None):
    """Initialize the UniqueTransactionRef object

    :param file: an absolute path to a .json file containing the transaction
    reference number, as an integer
    """
    self.file = file if file else self.default_file
    self.num = 0
    self.load()

    def __iter__(self):
    return self

    def __next__(self):
    """Increment the self.num attribute. Save the value to the local file.

    :returns: a string formatted version of the self.num class attribute
    """
    self.num += 1
    self.save()
    return str(self.num)

    def get(self):
    """Call the ``next`` function on self """
    return next(self)

    def load(self):
    """Load the transaction ref data from the local file

    :raises errors.UniqueTransactionRefError: Cannot find file
    """
    try:
    with open(self.file) as f:
    self.num = json.load(f)
    except FileNotFoundError:
    raise errors.UniqueTransactionRefError(
    self.file,
    num=self.num,
    message="Cannot find file",
    )

    def save(self):
    """Save self.num to the designated local file

    :raises UniqueTransactionRefError:
    """
    try:
    with open(self.file, "w") as f:
    json.dump(self.num, f)
    except Exception as e:
    raise errors.UniqueTransactionRefError(self.file,
    num=self.num,
    message=e)
    unique_trans_ref = UniqueTransactionRef() # module level variable


    Simplified example usage:



    class Bot:
    def __init__(self, unique_trans_ref):
    self.unique_trans_ref = unique_trans_ref

    def construct_order():
    trans_ref = next(self.unique_trans_ref)






    share|improve this question























      up vote
      7
      down vote

      favorite









      up vote
      7
      down vote

      favorite











      This code is a class I use in my financial market trading bot (note: I'm a daytrader-come-beginner programmer, not the other way around).



      Although I have the application running successfully, it has major design flaws which I intend to now address ASAP.



      An API requires that a unique transaction ref is submitted with each new order, otherwise, that order will be rejected. I have very little idea if this is a competent or robust design, I could not find any guidance on the issue elsewhere.



      I'm very much open to refactoring or a completely new design.



      class UniqueTransactionRef:
      """Transaction reference number iterator

      Loads, generates and saves unique transaction ref data for ``Bot`` orders

      :ivar file: absolute path the the .json transaction ref data file
      :ivar num: an integer representing the last generated transaction ref number
      """

      default_file = r"C:BotBottrans_ref.json"

      def __init__(self, file=None):
      """Initialize the UniqueTransactionRef object

      :param file: an absolute path to a .json file containing the transaction
      reference number, as an integer
      """
      self.file = file if file else self.default_file
      self.num = 0
      self.load()

      def __iter__(self):
      return self

      def __next__(self):
      """Increment the self.num attribute. Save the value to the local file.

      :returns: a string formatted version of the self.num class attribute
      """
      self.num += 1
      self.save()
      return str(self.num)

      def get(self):
      """Call the ``next`` function on self """
      return next(self)

      def load(self):
      """Load the transaction ref data from the local file

      :raises errors.UniqueTransactionRefError: Cannot find file
      """
      try:
      with open(self.file) as f:
      self.num = json.load(f)
      except FileNotFoundError:
      raise errors.UniqueTransactionRefError(
      self.file,
      num=self.num,
      message="Cannot find file",
      )

      def save(self):
      """Save self.num to the designated local file

      :raises UniqueTransactionRefError:
      """
      try:
      with open(self.file, "w") as f:
      json.dump(self.num, f)
      except Exception as e:
      raise errors.UniqueTransactionRefError(self.file,
      num=self.num,
      message=e)
      unique_trans_ref = UniqueTransactionRef() # module level variable


      Simplified example usage:



      class Bot:
      def __init__(self, unique_trans_ref):
      self.unique_trans_ref = unique_trans_ref

      def construct_order():
      trans_ref = next(self.unique_trans_ref)






      share|improve this question













      This code is a class I use in my financial market trading bot (note: I'm a daytrader-come-beginner programmer, not the other way around).



      Although I have the application running successfully, it has major design flaws which I intend to now address ASAP.



      An API requires that a unique transaction ref is submitted with each new order, otherwise, that order will be rejected. I have very little idea if this is a competent or robust design, I could not find any guidance on the issue elsewhere.



      I'm very much open to refactoring or a completely new design.



      class UniqueTransactionRef:
      """Transaction reference number iterator

      Loads, generates and saves unique transaction ref data for ``Bot`` orders

      :ivar file: absolute path the the .json transaction ref data file
      :ivar num: an integer representing the last generated transaction ref number
      """

      default_file = r"C:BotBottrans_ref.json"

      def __init__(self, file=None):
      """Initialize the UniqueTransactionRef object

      :param file: an absolute path to a .json file containing the transaction
      reference number, as an integer
      """
      self.file = file if file else self.default_file
      self.num = 0
      self.load()

      def __iter__(self):
      return self

      def __next__(self):
      """Increment the self.num attribute. Save the value to the local file.

      :returns: a string formatted version of the self.num class attribute
      """
      self.num += 1
      self.save()
      return str(self.num)

      def get(self):
      """Call the ``next`` function on self """
      return next(self)

      def load(self):
      """Load the transaction ref data from the local file

      :raises errors.UniqueTransactionRefError: Cannot find file
      """
      try:
      with open(self.file) as f:
      self.num = json.load(f)
      except FileNotFoundError:
      raise errors.UniqueTransactionRefError(
      self.file,
      num=self.num,
      message="Cannot find file",
      )

      def save(self):
      """Save self.num to the designated local file

      :raises UniqueTransactionRefError:
      """
      try:
      with open(self.file, "w") as f:
      json.dump(self.num, f)
      except Exception as e:
      raise errors.UniqueTransactionRefError(self.file,
      num=self.num,
      message=e)
      unique_trans_ref = UniqueTransactionRef() # module level variable


      Simplified example usage:



      class Bot:
      def __init__(self, unique_trans_ref):
      self.unique_trans_ref = unique_trans_ref

      def construct_order():
      trans_ref = next(self.unique_trans_ref)








      share|improve this question












      share|improve this question




      share|improve this question








      edited Feb 26 at 15:32









      Jamal♦

      30.1k11114225




      30.1k11114225









      asked Feb 26 at 13:23









      Dave

      634




      634




















          1 Answer
          1






          active

          oldest

          votes

















          up vote
          5
          down vote



          accepted










          The server requires a unique ID to detect replays in the case of network failures, support idempotency, and to report order confirmations in a way the client can make sense of. So yes, the server offers a sensible API.



          You can send sequential numbers, or a random guid. Consider using import uuid.



          Consider using a numeric prefix of yyyymmdd, with strftime('%Y%m%d') + '%06d' % num. This will help when you have issues with deleted file, backups, switching client laptops, and so on. It makes the transaction IDs more human readable. (It also makes them easier to guess, if you're concerned about a possible attacker.)



          Thank you for using with for I/O. Consider acquiring a lock before saving updated counter, if you're concerned that multiple daemons or users might run instances of your code concurrently.



          There's no need for default_file, as you can just put that default in the signature:



           def __init__(self, file=r"C:BotBottrans_ref.json"):


          You catch a subset of the things that can go wrong with file I/O and JSON parsing. It does not appear well motivated, given that the client doesn't try anyway, so it doesn't care whether it gets fatal exception A or B. Perhaps you have a use case which requires a custom exception, but you have not shown it. Likely you don't need it at this point. I would just let library load and open throw as they will, and caller will (correctly) receive fatal exception if one happens. Later, when caller implements an actual error recovery strategy, you will have new requirements in hand for what exception details must be returned, and you can make a better informed design decision about how UniqueTransactionRef should interact with exceptions.



          Write the simplest code you can get away with (it's easier to test!). When you get a new concrete requirement in hand, make the code a little fancier.






          share|improve this answer























          • Just for the record; str(uuid4()) is 400x faster than my implementation. My application creates approx 3000 orders per day, that's 13 secs of processing time saved.
            – Dave
            Feb 27 at 7:59










          Your Answer




          StackExchange.ifUsing("editor", function ()
          return StackExchange.using("mathjaxEditing", function ()
          StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix)
          StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
          );
          );
          , "mathjax-editing");

          StackExchange.ifUsing("editor", function ()
          StackExchange.using("externalEditor", function ()
          StackExchange.using("snippets", function ()
          StackExchange.snippets.init();
          );
          );
          , "code-snippets");

          StackExchange.ready(function()
          var channelOptions =
          tags: "".split(" "),
          id: "196"
          ;
          initTagRenderer("".split(" "), "".split(" "), channelOptions);

          StackExchange.using("externalEditor", function()
          // Have to fire editor after snippets, if snippets enabled
          if (StackExchange.settings.snippets.snippetsEnabled)
          StackExchange.using("snippets", function()
          createEditor();
          );

          else
          createEditor();

          );

          function createEditor()
          StackExchange.prepareEditor(
          heartbeatType: 'answer',
          convertImagesToLinks: false,
          noModals: false,
          showLowRepImageUploadWarning: true,
          reputationToPostImages: null,
          bindNavPrevention: true,
          postfix: "",
          onDemand: true,
          discardSelector: ".discard-answer"
          ,immediatelyShowMarkdownHelp:true
          );



          );








           

          draft saved


          draft discarded


















          StackExchange.ready(
          function ()
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f188375%2fa-class-to-generate-save-and-load-unique-transaction-reference-numbers-for-an-a%23new-answer', 'question_page');

          );

          Post as a guest






























          1 Answer
          1






          active

          oldest

          votes








          1 Answer
          1






          active

          oldest

          votes









          active

          oldest

          votes






          active

          oldest

          votes








          up vote
          5
          down vote



          accepted










          The server requires a unique ID to detect replays in the case of network failures, support idempotency, and to report order confirmations in a way the client can make sense of. So yes, the server offers a sensible API.



          You can send sequential numbers, or a random guid. Consider using import uuid.



          Consider using a numeric prefix of yyyymmdd, with strftime('%Y%m%d') + '%06d' % num. This will help when you have issues with deleted file, backups, switching client laptops, and so on. It makes the transaction IDs more human readable. (It also makes them easier to guess, if you're concerned about a possible attacker.)



          Thank you for using with for I/O. Consider acquiring a lock before saving updated counter, if you're concerned that multiple daemons or users might run instances of your code concurrently.



          There's no need for default_file, as you can just put that default in the signature:



           def __init__(self, file=r"C:BotBottrans_ref.json"):


          You catch a subset of the things that can go wrong with file I/O and JSON parsing. It does not appear well motivated, given that the client doesn't try anyway, so it doesn't care whether it gets fatal exception A or B. Perhaps you have a use case which requires a custom exception, but you have not shown it. Likely you don't need it at this point. I would just let library load and open throw as they will, and caller will (correctly) receive fatal exception if one happens. Later, when caller implements an actual error recovery strategy, you will have new requirements in hand for what exception details must be returned, and you can make a better informed design decision about how UniqueTransactionRef should interact with exceptions.



          Write the simplest code you can get away with (it's easier to test!). When you get a new concrete requirement in hand, make the code a little fancier.






          share|improve this answer























          • Just for the record; str(uuid4()) is 400x faster than my implementation. My application creates approx 3000 orders per day, that's 13 secs of processing time saved.
            – Dave
            Feb 27 at 7:59














          up vote
          5
          down vote



          accepted










          The server requires a unique ID to detect replays in the case of network failures, support idempotency, and to report order confirmations in a way the client can make sense of. So yes, the server offers a sensible API.



          You can send sequential numbers, or a random guid. Consider using import uuid.



          Consider using a numeric prefix of yyyymmdd, with strftime('%Y%m%d') + '%06d' % num. This will help when you have issues with deleted file, backups, switching client laptops, and so on. It makes the transaction IDs more human readable. (It also makes them easier to guess, if you're concerned about a possible attacker.)



          Thank you for using with for I/O. Consider acquiring a lock before saving updated counter, if you're concerned that multiple daemons or users might run instances of your code concurrently.



          There's no need for default_file, as you can just put that default in the signature:



           def __init__(self, file=r"C:BotBottrans_ref.json"):


          You catch a subset of the things that can go wrong with file I/O and JSON parsing. It does not appear well motivated, given that the client doesn't try anyway, so it doesn't care whether it gets fatal exception A or B. Perhaps you have a use case which requires a custom exception, but you have not shown it. Likely you don't need it at this point. I would just let library load and open throw as they will, and caller will (correctly) receive fatal exception if one happens. Later, when caller implements an actual error recovery strategy, you will have new requirements in hand for what exception details must be returned, and you can make a better informed design decision about how UniqueTransactionRef should interact with exceptions.



          Write the simplest code you can get away with (it's easier to test!). When you get a new concrete requirement in hand, make the code a little fancier.






          share|improve this answer























          • Just for the record; str(uuid4()) is 400x faster than my implementation. My application creates approx 3000 orders per day, that's 13 secs of processing time saved.
            – Dave
            Feb 27 at 7:59












          up vote
          5
          down vote



          accepted







          up vote
          5
          down vote



          accepted






          The server requires a unique ID to detect replays in the case of network failures, support idempotency, and to report order confirmations in a way the client can make sense of. So yes, the server offers a sensible API.



          You can send sequential numbers, or a random guid. Consider using import uuid.



          Consider using a numeric prefix of yyyymmdd, with strftime('%Y%m%d') + '%06d' % num. This will help when you have issues with deleted file, backups, switching client laptops, and so on. It makes the transaction IDs more human readable. (It also makes them easier to guess, if you're concerned about a possible attacker.)



          Thank you for using with for I/O. Consider acquiring a lock before saving updated counter, if you're concerned that multiple daemons or users might run instances of your code concurrently.



          There's no need for default_file, as you can just put that default in the signature:



           def __init__(self, file=r"C:BotBottrans_ref.json"):


          You catch a subset of the things that can go wrong with file I/O and JSON parsing. It does not appear well motivated, given that the client doesn't try anyway, so it doesn't care whether it gets fatal exception A or B. Perhaps you have a use case which requires a custom exception, but you have not shown it. Likely you don't need it at this point. I would just let library load and open throw as they will, and caller will (correctly) receive fatal exception if one happens. Later, when caller implements an actual error recovery strategy, you will have new requirements in hand for what exception details must be returned, and you can make a better informed design decision about how UniqueTransactionRef should interact with exceptions.



          Write the simplest code you can get away with (it's easier to test!). When you get a new concrete requirement in hand, make the code a little fancier.






          share|improve this answer















          The server requires a unique ID to detect replays in the case of network failures, support idempotency, and to report order confirmations in a way the client can make sense of. So yes, the server offers a sensible API.



          You can send sequential numbers, or a random guid. Consider using import uuid.



          Consider using a numeric prefix of yyyymmdd, with strftime('%Y%m%d') + '%06d' % num. This will help when you have issues with deleted file, backups, switching client laptops, and so on. It makes the transaction IDs more human readable. (It also makes them easier to guess, if you're concerned about a possible attacker.)



          Thank you for using with for I/O. Consider acquiring a lock before saving updated counter, if you're concerned that multiple daemons or users might run instances of your code concurrently.



          There's no need for default_file, as you can just put that default in the signature:



           def __init__(self, file=r"C:BotBottrans_ref.json"):


          You catch a subset of the things that can go wrong with file I/O and JSON parsing. It does not appear well motivated, given that the client doesn't try anyway, so it doesn't care whether it gets fatal exception A or B. Perhaps you have a use case which requires a custom exception, but you have not shown it. Likely you don't need it at this point. I would just let library load and open throw as they will, and caller will (correctly) receive fatal exception if one happens. Later, when caller implements an actual error recovery strategy, you will have new requirements in hand for what exception details must be returned, and you can make a better informed design decision about how UniqueTransactionRef should interact with exceptions.



          Write the simplest code you can get away with (it's easier to test!). When you get a new concrete requirement in hand, make the code a little fancier.







          share|improve this answer















          share|improve this answer



          share|improve this answer








          edited Feb 26 at 16:07


























          answered Feb 26 at 16:01









          J_H

          4,317129




          4,317129











          • Just for the record; str(uuid4()) is 400x faster than my implementation. My application creates approx 3000 orders per day, that's 13 secs of processing time saved.
            – Dave
            Feb 27 at 7:59
















          • Just for the record; str(uuid4()) is 400x faster than my implementation. My application creates approx 3000 orders per day, that's 13 secs of processing time saved.
            – Dave
            Feb 27 at 7:59















          Just for the record; str(uuid4()) is 400x faster than my implementation. My application creates approx 3000 orders per day, that's 13 secs of processing time saved.
          – Dave
          Feb 27 at 7:59




          Just for the record; str(uuid4()) is 400x faster than my implementation. My application creates approx 3000 orders per day, that's 13 secs of processing time saved.
          – Dave
          Feb 27 at 7:59












           

          draft saved


          draft discarded


























           


          draft saved


          draft discarded














          StackExchange.ready(
          function ()
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f188375%2fa-class-to-generate-save-and-load-unique-transaction-reference-numbers-for-an-a%23new-answer', 'question_page');

          );

          Post as a guest













































































          Popular posts from this blog

          Greedy Best First Search implementation in Rust

          Function to Return a JSON Like Objects Using VBA Collections and Arrays

          C++11 CLH Lock Implementation