template = """
# This neural network fitness template was auto generated by generate_nn_framework.py
#
# Rename this file and the gene_def file to prevent generate_nn_framework.py from detroying any changes
#   - be sure to update the corresponding generated gene_def template to capture the new file name (less the extention of .py)
#   - the gene_def template for this design is named: nn_template_gene_def.json
#
# This Neural Network contains:
#   #%{NN_NUM_INPUTS} Inputs
#   #%{NN_NUM_OUTPUTS} Outputs
#   #%{NN_NUM_HIDDEN_LAYERS} Hidden Layers
#   #%{NN_NUM_NEURONS_PER_HIDDEN_LAYER} Neurons Per Hidden Layer
#
#   * The neural network design is not editable. Re-run generate_nn_framework.py to change the design
#
# Modify the gene_def template to add any additional GA paramters but do not remove any of the _NN_ variables!!
# Include any added parameters to the init function below to allow the test sequencer to load thier values.   
#

import paths
import fitness
import neural_network
import math
import logging

logging.basicConfig(level=logging.WARNING)
logger = logging.getLogger(__name__)

class trade_engine(fitness.Fitness):
    def __init__(self):
        logger.info("init")
        #begining of generated code - do not edit!!
        self.init_weights()
        self.generate_weights_array()
        self._nn_num_inputs = #%{NN_NUM_INPUTS}
        self._nn_num_outputs = #%{NN_NUM_OUTPUTS}
        self._nn_num_hidden_layers = #%{NN_NUM_HIDDEN_LAYERS}
        self._nn_num_neurons_per_hidden_layer = #%{NN_NUM_NEURONS_PER_HIDDEN_LAYER}
        self._nn = neural_network.NeuralNet(self._nn_num_inputs,self._nn_num_outputs,self._nn_num_hidden_layers,self._nn_num_neurons_per_hidden_layer)
        fitness.Fitness.__init__(self) #call the base class to initialize internal variables
        self.reset()
        #end of generated code

        #insert implementation specific code here
        #modify the gene_def template to add any additional variables to optimize but do not remove any of the _NN_ variables!!
        return
        

    def generate_weights_array(self):
        #do not edit this function!!
        self.weights = []
        for v in self.__dict__:
            if v.find('_NN_') == 0:
                self.weights.append(self.__dict__[v])
        return

    def reset(self):
        logger.info("reset")
        fitness.Fitness.reset(self) #call the base class to reset internal variables: logs,period & score
        #insert custom reset code here
        return

    def run(self):
        logger.info("run")
        #do not edit!!
        self.generate_weights_array()
        self._nn.set_weights(self.weights) #apply the weighting inputs to the nn
        fitness.Fitness.run(self)

    def input(self,input_record):
        inputs = list(range(#%{NN_NUM_INPUTS})) 
        #add custom input signal routing code here
        #   - calculate custom inputs
        #   - or simply link the input record to the neural network
        #The number of inputs must match the neural network design of #%{NN_NUM_INPUTS} inputs

        #set the neural network inputs and receive the output
        outputs = self._nn.set_inputs(inputs)
        #handle the neural network outputs - this neural network will provide #%{NN_NUM_OUTPUTS} outputs

        #scoring can be implemented here as the outputs are provided, or at the end of the run when the score function is called
        fitness.Fitness.input(self,input_record) #increments the period count

    def score(self):
        logger.info("score")
        #insert custom scoring code here
        #make sure to protect for div by zero error
        return self.score_balance

    def cache_output(self,cache_name,periods=80000):
        self.cache.set(cache_name,self.logs.json())
        return

    def init_weights(self):
        #automaticaly generated - do not edit!!
#%{NN_WEIGHTS}
        return



if __name__ == '__main__':
    #test the custom fitness class
    c = trade_engine()
    c.input_file_name = "./datafeed/bcfeed_mtgoxUSD_1min.csv"
    c.initialize()
    c.run()
    print "score 1:",c.score()

    c.reset()

    c.initialize()
    c.run()
    print "score 2:",c.score()

    #score should be the same
    c.cache_input = True
    c.score_only = False
    c.reset()
    c.initialize()
    c.run()
    print "score 3:",c.score()

"""
