import pandas as pd
from datetime import date
from finam.export import Exporter, Market, Timeframe
import time
import threading
# === Загрузка стратегии ===
def load_strategy(filename='strategy.xlsx'):
df = pd.read_excel(filename)
df = df.dropna()
return df.to_dict(orient='records')
# === Загрузка свечей с Finam ===
exporter = Exporter()
TIMEFRAME_MAP = {
'1m': Timeframe.MINUTES1,
'5m': Timeframe.MINUTES5,
'15m': Timeframe.MINUTES15,
'30m': Timeframe.MINUTES30,
'1h': Timeframe.HOUR,
'h1': Timeframe.HOUR,
'h4': Timeframe.HOUR4,
'd': Timeframe.DAY,
}
def get_last_candle(symbol, timeframe):
try:
candles = exporter.download(
symbol=symbol,
market=Market.FUTURES, # Или SHARES для акций
timeframe=TIMEFRAME_MAP[timeframe],
start_date=date.today(),
end_date=date.today()
)
if candles.empty:
return None
return candles.iloc[-1]
except Exception as e:
print(f"Ошибка при получении свечи для {symbol} — {e}")
return None
# === Проверка сигнала ===
def is_signal_valid(candle, level, direction):
o, h, l, c = candle['OPEN'], candle['HIGH'], candle['LOW'], candle['CLOSE']
if direction == 'L':
return o > level and l < level and c > level
elif direction == 'S':
return o < level and h > level and c < level
return False
# === Цена заявки ===
def get_order_price(level, order_type, offset, direction):
if str(order_type).lower() == 'рыночная':
return 'market'
elif str(order_type).lower() == 'лимитная':
return level
elif str(order_type).lower() == 'люфтовая':
return level - offset if direction == 'S' else level + offset
return level
# === Стоп-лосс ===
def calculate_stop_loss(candle, tick, direction):
if direction == 'L':
return candle['LOW'] - tick
else:
return candle['HIGH'] + tick
# === Заявка и защитное время ===
def place_order(symbol, direction, lots, price):
print(f"\n➡️ Открытие позиции: {symbol} | {direction} | {lots} лотов | цена: {price}")
def delayed_stop_order(symbol, direction, stop_price, lots, delay_seconds):
def job():
print(f"⏳ Защитное время {delay_seconds} сек до стоп-заявки по {symbol}...")
time.sleep(delay_seconds)
close_side = 'buy' if direction == 'S' else 'sell'
print(f"❗ СТОП: {symbol} | Закрытие позиции {close_side} по рынку на {lots} лотов по цене: {stop_price}")
threading.Thread(target=job).start()
# === Главный цикл ===
def main():
strategy = load_strategy()
for row in strategy:
symbol = row['Symbol']
direction = row['Direction']
level = float(row['Level'])
lots = int(row['Lots'])
tick = float(row['Tick'])
timeframe = row['Timeframe']
offset = float(row.get('Offset', 0))
order_type = row['OrderType']
protect_time = int(row.get('ProtectTime', 0))
print(f"\n🔍 Проверка сигнала: {symbol}, {timeframe}")
candle = get_last_candle(symbol, timeframe)
if candle is None:
print(f"❌ Нет данных по {symbol}")
continue
if is_signal_valid(candle, level, direction):
print(f"✅ Сигнал подтвержден на {symbol} ({timeframe})")
price = get_order_price(level, order_type, offset, direction)
place_order(symbol, direction, lots, price)
stop_price = calculate_stop_loss(candle, tick, direction)
delayed_stop_order(symbol, direction, stop_price, lots, protect_time)
else:
print(f"🟡 Условия входа не выполнены для {symbol} ({timeframe})")
if __name__ == "__main__":
main()