Summing Results from a function running every 30 seconds - python

I've made a simple trading strategy, which executes every 30 seconds. I've defined the strategy in a function:
def strategy():
# strategy
time.sleep(30)
print(f'The Result from the Trade is: {result}')
Then I run it through a while loop:
while True:
strategy()
It's definitely not the best implementation, but it works for only testing a strategy. It shows me the result from each trade. However, I want to let it run through the whole day and accumulate and store the result from each trade in a variable, so I have the final result from all the trades from the whole day.
I've been looking at how to make this happen, but I can't find anything for the structure I have. Can someone help, please?

If you want to sum up the value returned you can do the following
strategy_output = 0
while True:
strategy_output =+ strategy()
If you want to save all the values till the last loop you can mantain the value in a dictionary corresponding to execution time
from datetime import datetime
strategy_output_dict = {}
while True:
now = datetime.now()
current_time = now.strftime("%H:%M:%S")
strategy_output = strategy()
strategy_output_dict[current_time] = strategy_output

Related

Why is the print func not working? Why is the print function not outputing at the specific time?

I am trying to print the current time at a specific time, how come it is not printing what I want it to do?
it is just exiting at code 0 when it get to the specific time(12:09)
from datetime import datetime as dt
now = dt.now()
current_time = now.strftime("%H:%M")
for i in range(500000000):
if current_time == "12:09":
print("The time is" + current_time)
You're only getting the time once. After you do current_time = now.strftime("%H:%M"), the current_time variable isn't going to change. If you want that, you need to move that code inside the loop so that they get run repeatedly:
for i in range(500000000):
now = dt.now() # move these lines
current_time = now.strftime("%H:%M") # inside the loop
if current_time == "12:09":
print("The time is" + current_time)
Note that this code is going to thrash your CPU pretty hard, since the loop doesn't take any significant amount of time, and will likely see the same time string thousands or more times in a row. You may want to call time.sleep or a similar function to delay 30+ seconds between checks of the time (since you only care about the minutes).

How to convert time written "h.mm" to decimal form with Python?

I prompt the user to input what time they start and finish their job. Then I need to calculate what they will earn (given a 97 currency/hour salary). The answer should also not have any decimals (so it should be rounded off). I can't seem to get it to work though.
As shown below, I tried taking the difference between the two inputs from the user and then splitting them to hours and minutes. After that just doing the calculations.
difference = round(float(finishing_time)-float(start_time), 2)
hours, minutes = str(difference).split(".")
salary_hours = int(hours)*97
salary_minutes = int(minutes)//60*97
salary = salary_hours + salary_minutes
So if start_time = 8.30 and finishing_time = 11.15 the salary should be 267, but I get 291 currency.
A couple of things to be careful of, is the rounding off that occurs at every level, which also occurs when you do math by hand and pencil! There is a reason why when you perform calculations one typically does the rounding off when the entire calculation has been performed otherwise one would come up with a vastly different answer as you pointed out.
I'd tackle this perhaps by doing something like this
from datetime import datetime
# quick way to generate a datetime object with start time would be like
start_time = datetime.now()
# replace the hours and minutes you want in your case its
start_time = start_time.replace(hour=8, minute=30)
end_time = start_time.replace(hour=11, minute=15)
# calling replace returns a new distinct datetime object
def calculate_salary(start_time, finish_time, pay_rate):
# will be in seconds
delta_seconds = finish_time - start_time
# convert to hours
hours_worked = (delta_seconds.seconds) / 3600
# calculate pay
pay = hours_worked * pay_rate
return pay
In this case calling the function gives a value of
In [1]: calculate_salary(start_time, end_time, 97)
Out[1]: 266.75
While i dont advocate doing calculations on time without a time module. I assume you know what your doing and that your calculations are simple I.E they wont rolle over midnight and the finish time will always be greater than the start time and finish on the same day. With that in mind the following code should produce your result without using a datetime module. However like #william bright answer, a datetime module would be my prefernce for code like this.
def get_hours(time_string):
time_split = time_string.split(".")
whole_hours = int(time_split[0])
fraction_hours = int(time_split[1]) / 60
return whole_hours + fraction_hours
start_time=input("start time: ")
finish_time=input("finish_time: ")
total_hours = get_hours(finish_time)-get_hours(start_time)
salary = total_hours*97
print(round(salary))
OUTPUT
start time: 8.30
finish_time: 11.15
267
So, my bad for perhaps being unclear in my statement, but since this is a work in progress for the next couple weeks/months, what I came up with was the following:
starting_time = input("At what time did you start working? ")
finishing_time = input("At what time did you finish working? ")
hours1, minutes1 = starting_time.split(".")
hours2, minutes2 = finishing_time.split(".")
minutes1 = float(minutes1)/60
starting_time_new = float(hours1)+minutes1
minutes2 = float(minutes2)/60
finishing_time_new = float(hours2)+minutes2
salary = round((finishing_time_new-starting_time_new)*97)
print("Started working at:",b)
print("Stopped working at:",s)
print("Your salary is",salary,"currency.")
The solution from where I started was to just focus on changing the minutes to the correct decimals instead of focusing on the hours too.
I am well aware that it is far from perfect, in fact, it is probably really bad. However, I am new to programming in Python and taking a course to be better.

Make a loop last once second using datetime?

Bright minds of Stackoverflow, I have a quest for you.
Currently I am running a loop in which calculations and data aquisition happen. These get more and more complicated over time. I want each run of the loop to last exactly one second. Due to the growing time of the calculations a simple "sleep(1)" at the end does not really help.
while True:
#here calculations happen that take more and more time
print 'some of the data'
sleep(1)
I was hoping to use datetime to calculate the seconds/milliseconds before these calculations and after to enter the difference into the sleep command. But i can't quite get my head around it. Can anyone help me out?
a=datetime.now()
#calculations
b=datetime.now()
calctime=(b-a).total_seconds()
sleep(1-calctime)
Try this:
from datetime import datetime
import time
def test():
a = datetime.now()
# calculations
b = datetime.now()
calctime = (b - a).total_seconds()
print("one")
time.sleep((1 - calctime) if (1-calctime)>0.0 else 0) #if your calculation already took 1 or more than 1 second then then make the waiting time 0
print("two")
test()
a=datetime.now()
#calculations
b=datetime.now()
calctime=b-a
ms = calctime.microseconds
if calctime.seconds == 0:
sleep(1-ms/1000000)
Additional info here: Python speed testing - Time Difference - milliseconds

Python: How to compare two hours

I need to call a function, exactly 08:00, 18:00, 22:00 hours. I've created a example to test the comparison between hours. When the current time reaches one of those horary. Put in inside a While loop thinking this example would work as a stopwatch, but I think I'm wrong. How is the best way to compare those values?
currentH= dt.datetime.now().strftime("%H:%M:%S")
h = "16:15:10"
while True:
if(currentH==h):
print 'Ok'
print 'The current Hour is: '+h
import datetime as dt
import time
currentH= dt.datetime.now().replace(microsecond=0).time()
hrs = ['00:02', '12:00']
for i in range(len(hrs)):
h = [int(x) for x in hrs[i].split(':')]
h = dt.datetime.now().replace(hour=h[0], minute=h[1], second=0,microsecond=0).time()
hrs[i] = h
while True:
currentH = dt.datetime.now().replace(microsecond=0).time()
print(currentH)
if currentH in hrs:
print('Time is now',currentH)
time.sleep(1)
The biggest problem with your code is that you never call now() again inside the loop, so you're just spinning forever comparing the initial time to 16:15:10.
While we're at it: Why convert the time to a string for comparison instead of just comparing times?
But there are bigger problems with this design that can't be fixed as easily.
What happens if you check the time at 16:15, then go to sleep, then wake up at 16:25? Then now() never returns 16:15:10.
Also, do you really want to burn 100% CPU for 10 hours?
A better solution is to write a sleep_until function:
def sleep_until(target):
left = target - dt.datetime.now()
if left > dt.timedelta(seconds=0):
time.sleep(left.total_seconds())
(If you're using Python 2.7 or 3.4, it's a bit more complicated, because sleep will wake up early if there's a signal. But to handle that case, you just need to add a while True: loop around the whole thing.)
Now, the only tricky bit is working out the first time you need to sleep until, which isn't all that tricky:
waits = itertools.cycle(dt.timedelta(hours=wait) for wait in (10, 4, 10))
now = dt.datetime.now()
start = dt.datetime.combine(dt.date.today(), dt.time(hour=8))
for wait in waits:
start += wait
if start > now:
break
And now, we just loop over the waits forever, sleeping until each next time:
for wait in waits:
sleep_until(start)
print('Time to make the donuts')
start += wait
Or, of course, you could just grab one of the many scheduling libraries off PyPI.
Or just use your platform's cron/launchd/Scheduled Tasks API to run your script.

Python: execute a function a random number of times per day

I'd like to execute a function a random number of times each day between set periods. Here's what I have so far:
def get_epochtime(dt=datetime.now()):
EPOCH = datetime(1970, 1, 1)
return (dt - EPOCH).total_seconds()
def get_todays_run_schedule(runs_per_day, run_between):
now = datetime.now()
window_start = now.replace(hour=run_between[0])
window_end = now.replace(hour=run_between[1])
the_schedule = [ get_epochtime(radar.random_datetime(start=window_start, stop=window_end)) for t in range(randint(runs_per_day[0], runs_per_day[1])) ]
the_schedule.sort()
print("Today I will run %s times" % len(the_schedule))
for run_at in the_schedule:
print("I will run at " + time.strftime("%Y-%m-%d %H:%M", time.localtime(run_at)))
return the_schedule
# we will run between 2 and 4 times per day between the hours of 10 AM and 5 PM.
schedule = get_todays_run_schedule((2, 4), (10, 17))
while(True):
now = datetime.now()
nowsecs = get_epochtime(now)
if now.hour == 0 and now.minute == 0 and now.second == 0:
schedule = get_todays_run_schedule()
if nowsecs in schedule:
execute_my_function
sleep(1)
Basically the idea is that at midnight and at first run, we come up with a run schedule which is a list of epoch times, the length of which is between two supplied integers. Each second we check the time and if the current time is within the list of run times, we execute our function. Finally, we sleep until the next second.
However, it isn't working at all. I suspect this might be because my datetime objects somehow include microseconds which is throwing off the comparison, but it could be because of something I'm not understanding about the nature of date time comparisons in python.
It's true that microseconds will be a problem for you here—both the objects in your list and the now will have microseconds, and running a loop only about once/second, the chance of any of those nows exactly matching an event timestamp are pretty slim.
But even if you fix that by truncating both now and the values in the list to seconds, that still won't solve the problem, it'll just make it an intermittent problem that's harder to debug. Consider what happens if you have an event at 15:25:26, and you start the loop at 15:25:25.907. You truncate that to 15:25:25, look it up, it's not there. Then you sleep for about a second, and call now(), and you get, say, 15:25:27.033. You truncate that to 15:25:27, look it up, and it's not there either.
Since you've already sorted the list, you can do something a whole lot simpler, which I'll demonstrate below. But first: While we're at it, the whole point of datetime objects is that they can do time comparisons, arithmetic, etc. directly, so you don't need to convert everything to numbers with something like your get_epochtime.
yesterday = datetime.today() - datetime.timedelta(days=1)
while True:
now = datetime.now()
if now.date() > yesterday:
schedule = get_todays_run_schedule()
yesterday = now.date()
while schedule and now >= schedule[0]:
del schedule[0]
execute_my_function
sleep(1)
(Obviously you'll also need to change get_todays_run_schedule to return a list of datetime objects instead of a list of floats to do it this way, but you should be able to figure that out.)
Also, notice that this way, we always know the time until the next event, so we don't need to loop around sleep(1) and keep waking the computer every second while it's on battery. You can just sleep(schedule[0] - now) when there is a next event, or sleep until midnight when there isn't. Or, maybe more simply, generate tomorrow's schedule when schedule goes empty, and then just sleep until its schedule[0].
In fact, if you think about it, you should be able to figure how to turn this into a loop in this form:
while True:
schedule = make_today_or_tomorrow_schedule()
for event in schedule:
while datetime.now() < event:
sleep(event - datetime.now())
execute_my_function

Categories