File size: 15,346 Bytes
812db64
653bb3e
 
 
 
 
 
 
812db64
653bb3e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
812db64
653bb3e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3451865
653bb3e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3451865
653bb3e
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
import gradio as gr
import random
from PIL import Image
import numpy as np
import os
import matplotlib.pyplot as plt
from io import BytesIO
import base64

# Candlestick patterns data
candlestick_patterns = [
    {
        "name": "Doji",
        "image": "doji.png",
        "signal": "neutral",
        "explanation": "A Doji forms when the opening and closing prices are virtually equal. It represents indecision in the market and can signal a potential reversal or continuation depending on previous price action."
    },
    {
        "name": "Hammer",
        "image": "hammer.png",
        "signal": "buy",
        "explanation": "The Hammer is a bullish reversal pattern that forms during a downtrend. It has a small body at the top with a long lower shadow (at least twice the size of the body). This indicates that sellers drove prices down during the session but buyers were able to push the price back up by closing."
    },
    {
        "name": "Shooting Star",
        "image": "shooting_star.png",
        "signal": "sell",
        "explanation": "The Shooting Star is a bearish reversal pattern that forms during an uptrend. It has a small body at the bottom with a long upper shadow. This signals that buyers pushed prices up during the session, but sellers took control and drove the price back down."
    },
    {
        "name": "Bullish Engulfing",
        "image": "bullish_engulfing.png",
        "signal": "buy",
        "explanation": "A Bullish Engulfing pattern forms when a small bearish candle is followed by a larger bullish candle that completely 'engulfs' the previous day's body. This indicates strong buying pressure and often signals a bullish reversal."
    },
    {
        "name": "Bearish Engulfing",
        "image": "bearish_engulfing.png",
        "signal": "sell",
        "explanation": "A Bearish Engulfing pattern forms when a small bullish candle is followed by a larger bearish candle that completely 'engulfs' the previous day's body. This indicates strong selling pressure and often signals a bearish reversal."
    },
    {
        "name": "Morning Star",
        "image": "morning_star.png",
        "signal": "buy",
        "explanation": "The Morning Star is a bullish reversal pattern consisting of three candles: a large bearish candle, followed by a small-bodied candle (star) that gaps down, followed by a large bullish candle that closes above the midpoint of the first candle. This shows a shift from selling to buying pressure."
    },
    {
        "name": "Evening Star",
        "image": "evening_star.png",
        "signal": "sell",
        "explanation": "The Evening Star is a bearish reversal pattern consisting of three candles: a large bullish candle, followed by a small-bodied candle (star) that gaps up, followed by a large bearish candle that closes below the midpoint of the first candle. This shows a shift from buying to selling pressure."
    },
    {
        "name": "Three White Soldiers",
        "image": "three_white_soldiers.png",
        "signal": "buy",
        "explanation": "The Three White Soldiers pattern consists of three consecutive bullish candles, each opening within the previous candle's body and closing above the previous candle's high. It signals strong buying pressure and often indicates a bullish reversal."
    }
]

# Generate placeholder images (since we don't have actual images)
def generate_candlestick_image(pattern_name):
    fig, ax = plt.subplots(figsize=(6, 3))
    
    # Different patterns have different appearances
    if pattern_name == "Doji":
        # Create a doji candlestick (open/close at same level)
        plt.plot([1], [50], 'ro', markersize=10)
        plt.plot([1], [30], '_', markersize=20, color='black')
        plt.plot([1], [70], '_', markersize=20, color='black')
        plt.plot([1, 1], [30, 70], 'k-')
    elif pattern_name == "Hammer":
        # Create a hammer candlestick
        plt.bar([1], [5], bottom=[45], width=0.4, color='green')
        plt.plot([1.2], [30], '_', markersize=20, color='black')
        plt.plot([1.2, 1.2], [30, 50], 'k-')
    elif pattern_name == "Shooting Star":
        # Create a shooting star candlestick
        plt.bar([1], [5], bottom=[45], width=0.4, color='red')
        plt.plot([1.2], [70], '_', markersize=20, color='black')
        plt.plot([1.2, 1.2], [50, 70], 'k-')
    elif pattern_name == "Bullish Engulfing":
        # First candle (small bearish)
        plt.bar([0.7], [5], bottom=[50], width=0.4, color='red')
        plt.plot([0.7, 0.7], [45, 55], 'k-')
        # Second candle (large bullish engulfing)
        plt.bar([1.3], [15], bottom=[40], width=0.4, color='green')
        plt.plot([1.3, 1.3], [35, 60], 'k-')
    elif pattern_name == "Bearish Engulfing":
        # First candle (small bullish)
        plt.bar([0.7], [5], bottom=[50], width=0.4, color='green')
        plt.plot([0.7, 0.7], [45, 55], 'k-')
        # Second candle (large bearish engulfing)
        plt.bar([1.3], [15], bottom=[40], width=0.4, color='red')
        plt.plot([1.3, 1.3], [35, 60], 'k-')
    elif pattern_name == "Morning Star":
        # First candle (large bearish)
        plt.bar([0.5], [10], bottom=[50], width=0.3, color='red')
        plt.plot([0.5, 0.5], [48, 62], 'k-')
        # Second candle (small doji)
        plt.bar([1], [2], bottom=[45], width=0.3, color='gray')
        plt.plot([1, 1], [44, 48], 'k-')
        # Third candle (large bullish)
        plt.bar([1.5], [10], bottom=[43], width=0.3, color='green')
        plt.plot([1.5, 1.5], [40, 55], 'k-')
    elif pattern_name == "Evening Star":
        # First candle (large bullish)
        plt.bar([0.5], [10], bottom=[45], width=0.3, color='green')
        plt.plot([0.5, 0.5], [43, 57], 'k-')
        # Second candle (small doji)
        plt.bar([1], [2], bottom=[58], width=0.3, color='gray')
        plt.plot([1, 1], [57, 61], 'k-')
        # Third candle (large bearish)
        plt.bar([1.5], [10], bottom=[45], width=0.3, color='red')
        plt.plot([1.5, 1.5], [43, 57], 'k-')
    elif pattern_name == "Three White Soldiers":
        # Three consecutive bullish candles
        plt.bar([0.5], [7], bottom=[40], width=0.3, color='green')
        plt.plot([0.5, 0.5], [38, 50], 'k-')
        plt.bar([1], [7], bottom=[47], width=0.3, color='green')
        plt.plot([1, 1], [45, 57], 'k-')
        plt.bar([1.5], [7], bottom=[54], width=0.3, color='green')
        plt.plot([1.5, 1.5], [52, 64], 'k-')
    
    plt.title(f"{pattern_name} Pattern")
    plt.xlim(0, 2)
    plt.ylim(20, 80)
    plt.axis('off')
    plt.tight_layout()
    
    # Convert plot to image
    buf = BytesIO()
    plt.savefig(buf, format='png')
    plt.close(fig)
    buf.seek(0)
    img = Image.open(buf)
    return img

# Function to generate quiz questions
def generate_questions(num_questions=10):
    questions = []
    for i in range(num_questions):
        pattern_index = i % len(candlestick_patterns)
        current_pattern = candlestick_patterns[pattern_index]
        
        # Create options (all patterns except the correct one)
        other_options = [p["name"] for p in candlestick_patterns if p["name"] != current_pattern["name"]]
        
        # Randomly select 3 incorrect options
        random.shuffle(other_options)
        shuffled_options = other_options[:3]
        
        # Add the correct answer and shuffle again
        shuffled_options.append(current_pattern["name"])
        random.shuffle(shuffled_options)
        
        questions.append({
            "pattern": current_pattern,
            "options": shuffled_options,
            "correct_answer": current_pattern["name"]
        })
    
    return questions

# Quiz state (will be managed in session state)
class QuizState:
    def __init__(self):
        self.reset()
    
    def reset(self):
        self.questions = generate_questions(10)
        self.current_question_index = 0
        self.score = 0
        self.answered = False
        self.selected_option = None
        self.is_complete = False

# Initialize quiz state
quiz_state = QuizState()

def get_current_question():
    return quiz_state.questions[quiz_state.current_question_index]

def create_interface():
    with gr.Blocks(css="""
        .container { max-width: 800px; margin: 0 auto; }
        .header { background-color: #4338ca; color: white; padding: 20px; border-radius: 10px; text-align: center; margin-bottom: 20px; }
        .quiz-container { background-color: white; border-radius: 8px; padding: 20px; margin-bottom: 20px; }
        .option { background-color: #f3f4f6; border: 2px solid #e2e8f0; border-radius: 8px; padding: 15px; margin-bottom: 10px; cursor: pointer; }
        .option:hover { background-color: #e2e8f0; }
        .correct { border-color: #10b981; background-color: rgba(16, 185, 129, 0.1); }
        .incorrect { border-color: #ef4444; background-color: rgba(239, 68, 68, 0.1); }
        .selected { border-color: #4338ca; background-color: rgba(67, 56, 202, 0.1); }
        .explanation { background-color: #f1f5f9; border-left: 4px solid #4338ca; padding: 15px; border-radius: 0 8px 8px 0; margin-bottom: 20px; }
        .signal { display: inline-block; padding: 6px 12px; border-radius: 4px; color: white; font-weight: bold; margin-bottom: 10px; }
        .buy { background-color: #10b981; }
        .sell { background-color: #ef4444; }
        .neutral { background-color: #6b7280; }
        .cash-reward { background-color: #fbbf24; color: #1f2937; padding: 10px 20px; border-radius: 8px; font-size: 24px; font-weight: bold; display: inline-block; margin: 20px 0; }
    """) as demo:
        gr.HTML("""
        <div class="header">
            <h1>Candlestick Pattern Quiz Game</h1>
            <p>Test your knowledge of candlestick patterns and earn reward points!</p>
        </div>
        """)
        
        with gr.Group(visible=True) as quiz_container:
            progress = gr.HTML(value="Question: 1/10 | Score: 0")
            
            pattern_image = gr.Image(label="Candlestick Pattern", type="pil")
            question_text = gr.Markdown("## What candlestick pattern is shown above?")
            
            with gr.Row():
                with gr.Column():
                    option1 = gr.Button(value="Option 1")
                    option2 = gr.Button(value="Option 2")
                with gr.Column():
                    option3 = gr.Button(value="Option 3")
                    option4 = gr.Button(value="Option 4")
            
            explanation_box = gr.Markdown(visible=False)
            next_button = gr.Button("Next Question", interactive=False)
        
        with gr.Group(visible=False) as results_container:
            gr.Markdown("## Quiz Complete!")
            final_score = gr.Markdown("Your final score: 0/10")
            cash_reward = gr.HTML('<div class="cash-reward">Reward: $0.00</div>')
            gr.Markdown("You've earned points that can be converted to cash rewards!")
            restart_button = gr.Button("Try Again")
        
        # Functions to update the interface
        def update_progress():
            return f"Question: {quiz_state.current_question_index + 1}/10 | Score: {quiz_state.score}"
        
        def load_question():
            if quiz_state.is_complete:
                return {
                    quiz_container: gr.update(visible=False),
                    results_container: gr.update(visible=True),
                    final_score: f"Your final score: {quiz_state.score}/10",
                    cash_reward: f'<div class="cash-reward">Reward: ${(quiz_state.score * 0.5):.2f}</div>'
                }
            
            question = get_current_question()
            img = generate_candlestick_image(question["pattern"]["name"])
            
            return {
                progress: update_progress(),
                pattern_image: img,
                option1: question["options"][0],
                option2: question["options"][1],
                option3: question["options"][2],
                option4: question["options"][3],
                explanation_box: gr.update(value="", visible=False),
                next_button: gr.update(interactive=False)
            }
        
        def select_option(option_text, btn_index):
            if quiz_state.answered:
                return {}
            
            quiz_state.selected_option = option_text
            quiz_state.answered = True
            
            question = get_current_question()
            correct = option_text == question["correct_answer"]
            
            if correct:
                quiz_state.score += 1
            
            # Prepare explanation
            pattern = question["pattern"]
            signal_class = "buy" if pattern["signal"] == "buy" else "sell" if pattern["signal"] == "sell" else "neutral"
            
            explanation_html = ""
            if correct:
                explanation_html += "### Correct! 🎉\n"
            else:
                explanation_html += f"### Incorrect\nThe correct answer is: **{question['correct_answer']}**\n"
            
            explanation_html += f"<div class='signal {signal_class}'>{pattern['signal'].upper()}</div>\n\n"
            explanation_html += pattern["explanation"]
            
            # Update button styles
            button_updates = {}
            for i, opt_text in enumerate([option1.value, option2.value, option3.value, option4.value]):
                btn_key = [option1, option2, option3, option4][i]
                if opt_text == question["correct_answer"]:
                    button_updates[btn_key] = gr.update(variant="primary", value=f"✓ {opt_text}")
                elif opt_text == option_text and not correct:
                    button_updates[btn_key] = gr.update(variant="stop", value=f"✗ {opt_text}")
            
            return {
                **button_updates,
                explanation_box: gr.update(value=explanation_html, visible=True),
                next_button: gr.update(interactive=True),
                progress: update_progress()
            }
        
        def next_question():
            quiz_state.current_question_index += 1
            quiz_state.answered = False
            quiz_state.selected_option = None
            
            if quiz_state.current_question_index >= len(quiz_state.questions):
                quiz_state.is_complete = True
            
            return load_question()
        
        def restart_quiz():
            quiz_state.reset()
            return {
                quiz_container: gr.update(visible=True),
                results_container: gr.update(visible=False),
                **load_question()
            }
        
        # Set up event handlers
        option1.click(lambda: select_option(option1.value, 0))
        option2.click(lambda: select_option(option2.value, 1))
        option3.click(lambda: select_option(option3.value, 2))
        option4.click(lambda: select_option(option4.value, 3))
        next_button.click(next_question)
        restart_button.click(restart_quiz)
        
        # Initialize the quiz
        demo.load(load_question)
    
    return demo

# Create and launch the interface
demo = create_interface()

# For Hugging Face Spaces
if __name__ == "__main__":
    demo.launch()