Implementing an observer class in python - python-3.x

I am creating a bidding system where students can log in to a system and make a request for a tutor and sign a contract via a TKinter UI. I have managed to do this successfully. But now I am required to do the following,
"when a student or a tutor logs in into the system, the system should notify the user if there is a contract that is going to expire within a month."
I am having trouble trying to implement this feature as I feel this needs an observer and I for the life of me can't wrap my head around the Observer design pattern. I have no problem creating the methods to call for the contracts and determine which contract expires but I can't seem to figure out how to like display it using an observer. Can I get some guidance on this?
For reference, this is the method that would get all the contracts that are expiring within a month.
def expiring_contracts(self,username):
user_contracts = self.all_contracts_by_user(username)
expiring_contracts = []
for i in user_contracts:
time_string = i["expiryDate"]
time_datetime = datetime.strptime(time_string,'%Y-%m-%dT%H:%M:%S.%f')
one_month = datetime.now() + dateutil.relativedelta.relativedelta(months=1)
if time_datetime < one_month:
expiring_contracts.append(i)
return expiring_contracts
the self.all_contracts_by_user is another method within this class that gets all the contracts by this user. I must implement a design pattern for this.

Related

Use One TradingView Strategy for Multiple Coins connected to Bot

I'm a newbie for TradingView and have been learning a lot. I'm developing a strategy with backtesting using pine-script language however what confusing me, is how to use the same strategy for multiple coins.
The strategy is mainly developed for Binance Futures trading not sure if possible to apply it to other Exchangers.
So I wanna setup alerting system for multiple coins to be connected to 3comma Bot or Finandy to execute a trade based on the setup parameter.
My questions are.
If I wanna use certain candle types like Hiken Ashi should that be included in the code or just select it in the chart and it will be read by the strategy automatically?
Should I include the coins in the script or I should select them one by one in the chart and then setup an alert per coin?
Should I create one alert per one coin per chart or I should have multiple charts per each coin to setup an alert?
Should the timeframe also be defined in the code or the chart can do the job?
Sorry for many questions, I'm trying to understand the process well.
For multiple coins, the easiest way is to attach your strategy to each and every coin on Tradingview you want to trade with. This way you can backtest each on their respective chart.
If you create a strategy for say BINANCE:BTCUSDT and think of using this strategy on different exchange, you can do it, but first I suggest test it on BINANCE:BTCPERP and see for yourself how the same strategy can show a wildly different result (even though BTCUSDT and BTCPERP should be moving the same).
For a complex solution you can create a single script that uses multiple securities, but you won't be able to backtest that with simple approach, you would have to write your own gain/loss calculator, and you are not there yet.
I was going down the same road, my suggestions are:
create an input for the coin you want to trade (that will go into an input variable)
abstract the alert message off of the strategy.entry() command, that is, construct the alert message in a way you can replace values with variables in it (like the above selected coin)
3Commas needs a Bot ID to start/stop a bot, abstract that off as well, and you will have a good boilerplate code you can reuse many times
as a good practice (stolen from Kubernetes) besides the human readable name, I give a 5 letter identifier to every one of my bots, for easy recognition
A few examples. The below will create a selector for a coin and the Bot ID that is used to trade that coin. The names like 'BIN:GMTPERP - osakr' are entirely my making, they act as a Key (for a key/value pair):
symbol_choser = input.string(title='Ticker symbol', defval='BTC-PERP - aktqw', options=[FTX_Multi, 'FTX:MOVE Single - pdikr', 'BIN:GMTPERP - osakr', 'BIN:GMTPERP - rkwif', 'BTC-PERP - aktqw', 'BTC-PERP - ikrtl', 'BTC-PERP - cbdwe', 'BTC-PERP', 'BAL-PERP', 'RUNE-PERP', 'Paper Multi - fjeur', 'Paper Single - ruafh'], group = 'Bot settings')
exchange_symbol = switch symbol_choser // if you use Single Pair bots on 3Commas, the Value should be an empty string
'BIN:GMTPERP - osakr' => 'USDT_GMTUSDT'
'BTC-PERP - cbdwe' => 'USD_BTC-PERP'
'Paper Multi - fjeur' => 'USDT_ADADOWN'
bot_id = switch symbol_choser
'BIN:GMTPERP - osakr' => '8941983'
'BTC-PERP - cbdwe' => '8669136'
'Paper Multi - fjeur' => '8246237'
And now you can combine the above parts into two Alerts, for starting/stopping the bot:
alertMessage_Enter = '{"message_type": "bot", "bot_id": ' + bot_id + ', "email_token": "12345678-4321-abcd-xyzq-132435465768", "delay_seconds": 0, "pair": "' + exchange_symbol + '"}'
alertMessage_Exit = '{"action": "close_at_market_price", "message_type": "bot", "bot_id": ' + bot_id + ', "email_token": "12345678-4321-abcd-xyzq-132435465768", "delay_seconds": 0, "pair": "' + exchange_symbol + '"}'
exchange_symbol is the proper exchange symbol you need to provide to your bot, you can get help on the 3Commas' bot page (they have pre-crafted the HTTP requests you need to use for certain actions).
bot_id is the ID of your Bot, that is straightforward.
The above solution does not handle Single coin bots, their trigger message has a different structure.
Whenever you can, use Multi coin bots as they can act as a Single bot with two exception:
if you have a long spanning strategy and when you start a bot, you should be already in a trade, you can manually start a Single bot, but you cannot start a Multi coin bot (as there is no way to provide the coin info on which to start the trade)
if you are trading a derivative like FTX's MOVE contracts and your script is attached to the underlying BTC Futures. MOVE contracts changes name every day (the date is in their name, like: BTC-MOVE-0523) so you would need delete an alert, update and reapply the alert every day, etc. Instead, if your script is on the BTC-PERP then you can use a Single coin bot which does not expect a coin name in the alert message so it will start/stop the Bot on whatever coin it is connected to, then you need to change the coin name every day only in the Bot settings and never touch the Alert.
To summarize on your questions:
Do not include chart type in code (that is not even an embeddable data), just apply your code to whatever chart you want to use. Hint: never use Heikin-Ashi for trading. You can, but you will pay for it dearly (everyone tries, even against warnings, no worries)
Set up them one-by-one, so you can backtest them
No, set the timeframe on the chart. Later, when you will be more experienced you will be able to abstract the current timeframe (whatever it is) away and write code that is timeframe-agnostic. But that's hard and make your code less readable.

How to handle replies in with Pyrogram when using ForceReply?

I am building a telegram bot where I am attempting to get the user to fill in detail about an event and store them in a dictionary which is itself in a list.
However I want it be link a conversation. I want it to look like:
user: /create
bot-reply: What would you like to call it?
user-reply: Chris' birth day
bot-reply: When is it?
user-reply: 08/11/2021
bot-reply: Event Chris birth day on 08/11/2021 has been saved!
To achieve this I plan to use ForceReply which states in the documentation
This can be extremely useful if you want to create user-friendly step-by-step interfaces without having to sacrifice privacy mode.
The problem is the documentation does not seem to explain how to handle responses.
Currently my code looks like this:
#app.on_message(filters.command('create'))
async def create_countdown(client, message):
global countdowns
countdown = {
'countdown_id': str(uuid4())[:8],
'countdown_owner_id': message.from_user.id,
'countdown_onwner_username': message.from_user.username,
}
try:
await message.reply('What do you want to name the countdown?',
reply_markup=ForceReply()
)
except FloodWait as e:
await asyncio.sleep(e.x)
Looking through the form I have found options like this:
python telegram bot ForceReply callback
which are exactly what I am looking for but they are using different libraries like python-telegram-bot which permit them to use ConversationHandler. It seems to not be part of pyrogram
How to I create user-friendly step-by-step interfaces with pyrogram?
Pyrogram doesn't have a ConversationHandler.
You could use a dict with your users' ID as the key and the state they're in as the value, then you can use that dictionary of states as your reference to know where your User is in the conversation.
Dan: (Pyrogram creator)
A conversation-like feature is not available yet in the lib. One way to do that is saving states into a dictionary using user IDs as keys. Check the dictionary before taking actions so that you know in which step your users are and update it once they successfully go past one action
https://t.me/pyrogramchat/213488

Stripe: Getting Credit Card's Last 4 Digits

I have upgraded the Stripe.net to the latest version which is 20.3.0 and now I don't seem to find the .Last4 for the credit card. I had the following method:
public void CreateLocalCustomer(Stripe.Customer stipeCustomer)
{
var newCustomer = new Data.Models.Customer
{
Email = stipeCustomer.Email,
StripeCustomerId = stipeCustomer.Id,
CardLast4 = stipeCustomer.Sources.Data[0].Card.Last4
};
_dbService.Add(newCustomer);
_dbService.Save();
}
But now the stipeCustomer.Sources.Data[0].Card.Last4 says 'IPaymentSource' does not contain a definition for 'Card'. Does anyone know how I can get the card details now? The flow is that I create the customer by passing the Stripe token to Stripe, then I get the above stripeCustomer. So I expect it to be somewhere in that object. But I can't find it. The release notes can be found here.
Thank you.
In the old world of Stripe, there only used to be one type of payment method you could attach to a Customer; specifically, Card-objects. You would create a Card-object by using Stripe.js/v2 or the Create Token API Endpoint to first create a Token-object and then attach that token to a Customer-object with the Create Card API Endpoint.
Once Stripe expanded to support a number of other payment methods though, Stripe built support for a new object type that encapsulated a number of payment methods (including credit cards) called Source-objects. A Source-object is created either by using Stripe.js/v3 or the Create Source API Endpoint. It can also be attached to a Customer-object in much the same way as the Card-objects mentioned above, except they retain their object type. They're still a Source. You use the Attach Source API Endpoint to do this (that is notably identical to the Create Card API Endpoint mentioned above).
What I'm getting at here, is there are now two different object types (or more) that you can expect to see returned in the sources-array (or Sources in .NET). All of these methods though inherit from the IPaymentSource-interface. So if you know you have a Card-object getting returned, you can simply cast the returned object to the Card-class.
Something like this should get you going:
CardLast4 = ((Card) stipeCustomer.Sources.Data[0]).Last4
You can see what I mean by inheritance by looking at this line in the Card-class file:
https://github.com/stripe/stripe-dotnet/blob/master/src/Stripe.net/Entities/Cards/Card.cs#L7
Good luck!
As of Stripe.net.21.4.1, this is what works:
var chargeService = new ChargeService();
var charge = chargeService.Get(id);
CardLast4 = ((Card)charge.Source).Last4;
It's getting hard not to panic when code breaks because of all the micro-changes Stripe makes.
So after debugging, it looks like the Data[0] needs to be cast as Card to get the card.
So it will be CardLast4 = ((Card)stipeCustomer.Sources.Data[0]).Last4.

Where to put outside-aggregate validation?

I've got a question regarding outside-aggregate validation.
In our domain partner can place orders that contain certain products (1).
Once order is placed (2) he can mark it as paid (3) in our system.
Once order is marked as paid (4) we assign licences to products in external library service (5).
Once we know licences are assigned (6) we close entire saga.
Here's a small drawing illustrating the process:
At this moment besides commands, command handlers and events there are two domain classes that are involved in entire process:
Order aggregate containing business logic
Order saga coordinating entire process and assigning licences
Now, there is one invariant that is not modelled in this process yet - before we mark order as paid we have to check if user does not already have particular licence assigned. We get this from library service as well.
Where would you put this validation? Command handler? Wrap Order in some domain service? Pass some validator to Order constructor?
class Order
{
public function __construct(OrderValidator $validator)
{
if (!$validator->isValid($this)) {
throw new \DomainException();
}
// else proceed
}
}
class OrderValidator
{
private $libraryServiceClient;
public function isValid(Order $order)
{
// check licence using $libraryServiceClient
}
}
As far as I understood the problem is in step 3 (Mark order as payed). In this step we need a user (let's call it payer) that marks the order as payed. So when creating this payer object (using factory maybe) we need to know if he is allowed to mark an order as payed. In order to get this information a call should be made to the external library.
What I suggest is to have an application service that have ->markOrderAsPayed($orderId, $payerUserId)
This method will make a call to 2 domain services. One for getting the payer and one for marking the order as payed.
$payer = $this->payerService->getPayer($payerUserId);
$this->orderService->payOrder($orderId, $payer);
In the getPayer() function you should make a call to the external library to know how many licences the payer have.
I hope this will be helpful, it is just based on what I understood from the questions and comments.

cakePHP and authorization for CRUD operations

I have a cakephp 1.3 application and I have run into a 'data leak' security hole. I am looking for the best solution using cake and not just something that will work. The application is a grade tracking system that lets teachers enter grades and students can retrieve their grades. Everything is working as expected but when I started to audit security I found that the basic CRUD operations have leaks. Meaning that student X can see student Y's grades. Students should only see their own grades. I will limit this questions to the read operation.
Using cake, I have a grade_controller.php file with this view function:
function view($id = null) {
// Extra, not related code removed
$this->set('grade', $this->grade->read(null, $id));
}
And
http://localhost/grade/view/5
Shows the grade for student $id=5. That's great. But if student #5 manipulates the URL and changes it to a 6, person #6's grades are shown. The classic data leak security hole.
I had two thoughts on the best way to resolve this. 1) I can add checks to every CRUD operations called in the controller. Or 2) add code to the model (for example using beforeFind()) to check if person X has access to that data element.
Option #1 seems like it is time consuming and error prone.
Option #2 seem like the best way to go. But, it required calling find() before some operations. The read() example above never executes beforeFind() and there is no beforeRead() callback.
Suggestions?
Instead of having a generic read() in your controller, you should move ALL finds, queries..etc into the respective model.
Then, go through each model and add any type of security checks you need on any finds that need to be restricted. 1) it will be much more DRY coding, and 2) you'll better be able to manage security risks like this since you know where all your queries are held.
For your example, I would create a getGrade($id) method in my Grade model and check the student_id field (or whatever) against your Auth user id CakeSession::read("Auth.User.id");
You could also build some generic method(s) similar to is_owner() to re-use the same logic throughout multiple methods.
If CakePHP supports isAuthorized, here's something you could do:
Create a column, that has the types of users (eg. 'student', 'teacher', ...)
Now, it the type of User is 'student', you can limit their access, to view only their data. An example of isAuthorized is as follows. I am allowing the student to edit only their profile information. You can extend the concept.
if ((($role['User']['role'] & $this->user_type['student']) == $this->user_type['student']) {
if (in_array($this->action, array('view')) == true) {
$id = $this->params->pass[0];
if ($id == $user_id) {
return (true);
}
}
}
}

Resources