Skip to content

Commit

Permalink
updating fastscalping feature
Browse files Browse the repository at this point in the history
  • Loading branch information
marketcalls committed Aug 19, 2024
1 parent 7cbc732 commit 6981aaa
Show file tree
Hide file tree
Showing 7 changed files with 287 additions and 26 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ Thumbs.db
.vscode/
.idea/
.python-version
config.ini


#DB Files and Log/Tmp Files
Expand Down
19 changes: 11 additions & 8 deletions .sample.env
Original file line number Diff line number Diff line change
Expand Up @@ -7,22 +7,25 @@ REDIRECT_URL = 'http://127.0.0.1:5000/<broker>/callback' # Change if different
# OpenAlgo Application Key - Change the Key to Some Random Values
APP_KEY = 'dfsd98sdf98dsfjk34ghuu85df'


# OpenAlgo Database Configuration
DATABASE_URL = 'sqlite:///db/openalgo.db' # Change if using a different database
DATABASE_URL = 'sqlite:///db/openalgo.db'

# OpenAlgo Ngrok Configuration
NGROK_ALLOW = 'FALSE' # Set to 'TRUE' if using Ngrok
NGROK_ALLOW = 'FALSE'

# OpenAlgo Hosted Server (Custom Domain Name) or Ngrok Domain Configuration
HOST_SERVER = 'http://127.0.0.1:5000' # Change to your custom domain or Ngrok domain
# Change to your custom domain or Ngrok domain
HOST_SERVER = 'http://127.0.0.1:5000'

# OpenAlgo Flask App Host and Port Configuration
FLASK_HOST_IP='127.0.0.1' # For 0.0.0.0 (accessible from other devices on the network)
FLASK_PORT='5000' # Default Port is 5000
FLASK_DEBUG='False' # Set to 'False' in production
# For 0.0.0.0 (accessible from other devices on the network)
FLASK_HOST_IP='127.0.0.1'
FLASK_PORT='5000'
FLASK_DEBUG='False'

# OpenAlgo Flask App Version Management
FLASK_APP_VERSION='1.0.0.3'
FLASK_APP_VERSION='1.0.0.4'

# OpenAlgo Rate Limit Settings
LOGIN_RATE_LIMIT_MIN = "5 per minute"
Expand All @@ -33,4 +36,4 @@ API_RATE_LIMIT="10 per second"

# Required to give 0.5 second to 1 second delay between multi-legged option strategies
# Single legged orders are not affected by this setting.
SMART_ORDER_DELAY = '0.5' # Adjust as needed
SMART_ORDER_DELAY = '0.5'
52 changes: 35 additions & 17 deletions blueprints/dashboard.py
Original file line number Diff line number Diff line change
@@ -1,26 +1,24 @@
# Make sure to include the correct import path based on your project structure
from flask import Blueprint, render_template, session, redirect, url_for, g
from flask import Blueprint, render_template, session, redirect, url_for, g, jsonify, request
from database.auth_db import get_auth_token

from importlib import import_module
import multiprocessing
import sys

# Import the launch_trading_app function from fastscalper.py
from blueprints.fastscalper import launch_trading_app

def dynamic_import(broker):
try:
# Construct module path dynamically
module_path = f'broker.{broker}.api.funds'
# Import the module
module = import_module(module_path)
# Now, you can access get_margin_data or any other function directly
get_margin_data = getattr(module, 'get_margin_data')
return get_margin_data
except ImportError as e:
# Handle the error if module doesn't exist
print(f"Error importing module: {e}")
return None


dashboard_bp = Blueprint('dashboard_bp', __name__, url_prefix='/')
scalper_process = None

@dashboard_bp.route('/dashboard')
def dashboard():
Expand All @@ -30,25 +28,45 @@ def dashboard():
login_username = session['user']
AUTH_TOKEN = get_auth_token(login_username)


if AUTH_TOKEN is None:
return redirect(url_for('auth.logout'))
#print(f'The auth token is: {AUTH_TOKEN}')

# Ensure the broker is set in the session
broker = session.get('broker')
if not broker:
# Handle the case where the broker is not set
return "Broker not set in session", 400

# Dynamically import the get_margin_data function based on the broker
get_margin_data_func = dynamic_import(broker)
if get_margin_data_func is None:
# Handle the case where the dynamic import failed
return "Failed to import broker module", 500

# Use the dynamically imported get_margin_data function
margin_data = get_margin_data_func(AUTH_TOKEN)
return render_template('dashboard.html', margin_data=margin_data)

@dashboard_bp.route('/launch', methods=['POST'])
def launch_trading_tool():
global scalper_process

if not session.get('logged_in'):
return redirect(url_for('auth.login'))

login_username = session['user']
AUTH_TOKEN = get_auth_token(login_username)

if AUTH_TOKEN is None:
return redirect(url_for('auth.logout'))

broker = session.get('broker')
if not broker:
return "Broker not set in session", 400

# Terminate the previous process if it is still running
if scalper_process and scalper_process.is_alive():
scalper_process.terminate()
scalper_process.join()

if sys.platform.startswith('win'):
multiprocessing.freeze_support()

# Render the dashboard template with the margin data
return render_template('dashboard.html', margin_data=margin_data)
scalper_process = multiprocessing.Process(target=launch_trading_app)
scalper_process.start()
return jsonify({"message": "FastScalper Launched"}), 200
208 changes: 208 additions & 0 deletions blueprints/fastscalper.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,208 @@
import sys
import configparser
import customtkinter as ctk
from tkinter import messagebox, ttk
from openalgo.orders import api # Import the OpenAlgo package

class AppStyles:
BG_COLOR = "#1E1E1E"
INPUT_COLOR = "#2B2B2B"
LE_COLOR = "#4CAF50"
LX_COLOR = "#F44336"
SE_COLOR = "#FF9800"
SX_COLOR = "#0066cc"
SETTINGS_COLOR = "#2196F3"

class SettingsDialog(ctk.CTkToplevel):
EXCHANGES = [
"NSE", "NFO", "CDS", "BSE", "BFO", "BCD", "MCX", "NCDEX"
]
PRODUCTS = [
"CNC", "NRML", "MIS"
]

def __init__(self, parent, title, initial_values):
super().__init__(parent)
self.title(title)
self.initial_values = initial_values
self.result = {}
self.create_widgets()
self.grab_set()

self.update_idletasks()
x = parent.winfo_x() + (parent.winfo_width() - self.winfo_width()) // 2
y = parent.winfo_y() + (parent.winfo_height() - self.winfo_height()) // 2
self.geometry(f"+{x}+{y}")

def create_widgets(self):
self.entries = {}
for i, (key, value) in enumerate(self.initial_values.items()):
if key in ['exchange', 'product']:
ctk.CTkLabel(self, text=f"{key.capitalize()}:").grid(row=i, column=0, sticky="e", padx=5, pady=2)
combo = ttk.Combobox(self, values=self.EXCHANGES if key == 'exchange' else self.PRODUCTS, width=30)
combo.set(value)
combo.grid(row=i, column=1, sticky="we", padx=5, pady=2)
self.entries[key] = combo
else:
ctk.CTkLabel(self, text=f"{key.capitalize()}:").grid(row=i, column=0, sticky="e", padx=5, pady=2)
entry = ctk.CTkEntry(self, width=120)
entry.insert(0, value)
entry.grid(row=i, column=1, sticky="we", padx=5, pady=2)
self.entries[key] = entry

button_frame = ctk.CTkFrame(self)
button_frame.grid(row=len(self.initial_values), column=0, columnspan=2, pady=5)

ctk.CTkButton(button_frame, text="OK", command=self.on_ok, width=60).pack(side="left", padx=2)
ctk.CTkButton(button_frame, text="Cancel", command=self.on_cancel, width=60).pack(side="left", padx=2)

def on_ok(self):
for key, widget in self.entries.items():
self.result[key] = widget.get()
self.destroy()

def on_cancel(self):
self.result = None
self.destroy()

class TradingApp:
def __init__(self, master):
self.master = master
master.title("FastScalper")
master.configure(bg=AppStyles.BG_COLOR)

self.config = configparser.ConfigParser()
self.config_file = 'config.ini'
self.load_config()

self.create_widgets()
self.center_window()

def center_window(self):
self.master.geometry('300x100') # Set the explicit geometry to ensure correct size
self.master.update_idletasks() # Ensure all tasks are processed
width = self.master.winfo_width()
height = self.master.winfo_height()
x = (self.master.winfo_screenwidth() // 2) - (width // 2)
y = (self.master.winfo_screenheight() // 2) - (height // 2)
self.master.geometry('{}x{}+{}+{}'.format(width, height, x, y))
self.master.after(100, self.adjust_size) # Adjust the size after 100ms

def adjust_size(self):
self.master.geometry('300x100') # Forcefully set the size again

def create_widgets(self):
main_frame = ctk.CTkFrame(self.master, fg_color=AppStyles.BG_COLOR)
main_frame.pack(fill="both", expand=True, padx=5, pady=5)

input_frame = ctk.CTkFrame(main_frame, fg_color=AppStyles.BG_COLOR)
input_frame.pack(fill="x", pady=(0, 5))
self.create_input_field(input_frame, "Symbol", 0, "BHEL")
self.create_input_field(input_frame, "Quantity", 1, "1")
self.create_button(input_frame, "Settings", self.open_settings, AppStyles.SETTINGS_COLOR, 0, 2, rowspan=2)

button_frame = ctk.CTkFrame(main_frame, fg_color=AppStyles.BG_COLOR)
button_frame.pack(fill="x")

button_config = [
("LE", self.trade_le, AppStyles.LE_COLOR),
("LX", self.trade_lx, AppStyles.LX_COLOR),
("SE", self.trade_se, AppStyles.SE_COLOR),
("SX", self.trade_sx, AppStyles.SX_COLOR)
]

for i, (text, command, color) in enumerate(button_config):
self.create_button(button_frame, text, command, color, 0, i)

def create_input_field(self, parent, label, row, default_value):
ctk.CTkLabel(parent, text=f"{label}:", anchor="e", width=55).grid(row=row, column=0, padx=(0, 2), pady=1, sticky="e")
entry = ctk.CTkEntry(parent, width=120, fg_color=AppStyles.INPUT_COLOR)
entry.insert(0, default_value)
entry.grid(row=row, column=1, pady=1, sticky="w")
setattr(self, label.lower(), entry)

def create_button(self, parent, text, command, fg_color, row, column, rowspan=1):
button = ctk.CTkButton(parent, text=text, command=command, fg_color=fg_color, text_color="black", width=70, height=25)
button.grid(row=row, column=column, rowspan=rowspan, padx=1, pady=1)

def trade_le(self): self.trade("BUY", self.quantity.get())
def trade_lx(self): self.trade("SELL", 0)
def trade_se(self): self.trade("SELL", self.quantity.get())
def trade_sx(self): self.trade("BUY", 0)

def trade(self, action, quantity):
info = f"Action: {action}\n"
info += f"Symbol: {self.symbol.get()}\n"
info += f"Quantity: {quantity}\n"
info += f"API Key: {self.config['DEFAULT']['api_key']}\n"
info += f"Exchange: {self.config['DEFAULT']['exchange']}\n"
info += f"Product: {self.config['DEFAULT']['product']}\n"

print(f"--- {action} ---")
print(info)
print("--------------------")

# OpenAlgo Smart Order Integration
try:
client = api(api_key=self.config['DEFAULT']['api_key'], host='http://127.0.0.1:5000')
response = client.placesmartorder(
strategy="FastScalper", # Replace with your strategy
symbol=self.symbol.get(),
action=action,
exchange=self.config['DEFAULT']['exchange'],
price_type="MARKET", # Replace with your price type
product=self.config['DEFAULT']['product'],
quantity=int(quantity),
position_size=0 # Replace with your position size
)
'''
if response['status'] == 'success':
messagebox.showinfo("Order Status", f"Order placed successfully: {response['orderid']}")
else:
messagebox.showerror("Order Error", f"Order failed: {response['error']}")
'''
except Exception as e:
messagebox.showerror("OpenAlgo Error", str(e))

def open_settings(self):
initial_values = {k: self.config['DEFAULT'][k] for k in ['api_key', 'exchange', 'product']}
dialog = SettingsDialog(self.master, "Settings", initial_values)
self.master.wait_window(dialog)
if dialog.result:
self.config['DEFAULT'].update(dialog.result)
self.save_config()

def save_config(self):
with open(self.config_file, 'w') as configfile:
self.config.write(configfile)
messagebox.showinfo("Config Saved", "Configuration has been saved.")

def load_config(self):
self.config.read(self.config_file)
if 'DEFAULT' not in self.config:
self.config['DEFAULT'] = {
'api_key': 'xxxxxx',
'exchange': 'NSE',
'product': 'MIS'
}
else:
defaults = {'api_key': 'xxxxxx', 'exchange': 'NSE', 'product': 'MIS'}
for key, value in defaults.items():
if key not in self.config['DEFAULT']:
self.config['DEFAULT'][key] = value

def launch_trading_app():
if sys.platform.startswith('linux'):
# For Linux, ensure Tkinter is properly initialized
import tkinter as tk
root = tk.Tk()
root.withdraw()

ctk.set_appearance_mode("dark")
ctk.set_default_color_theme("blue")
root = ctk.CTk()
app = TradingApp(root)
root.mainloop()

if __name__ == "__main__":
launch_trading_app()
3 changes: 3 additions & 0 deletions requirements-nginx.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ cachetools==5.3.3
certifi==2024.7.4
charset-normalizer==3.3.2
click==8.1.7
customtkinter==5.2.2
darkdetect==0.8.0
Deprecated==1.2.14
Flask==3.0.3
Flask-Bcrypt==1.0.1
Expand Down Expand Up @@ -41,6 +43,7 @@ setuptools==70.3.0
simple-websocket==1.0.0
six==1.16.0
SQLAlchemy==2.0.31
tk==0.1.0
typing_extensions==4.12.2
tzdata==2024.1
urllib3==2.2.2
Expand Down
3 changes: 3 additions & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ cachetools==5.3.3
certifi==2024.7.4
charset-normalizer==3.3.2
click==8.1.7
customtkinter==5.2.2
darkdetect==0.8.0
Deprecated==1.2.14
Flask==3.0.3
Flask-Bcrypt==1.0.1
Expand Down Expand Up @@ -41,6 +43,7 @@ setuptools==70.3.0
simple-websocket==1.0.0
six==1.16.0
SQLAlchemy==2.0.31
tk==0.1.0
typing_extensions==4.12.2
tzdata==2024.1
urllib3==2.2.2
Expand Down
Loading

0 comments on commit 6981aaa

Please sign in to comment.