shortcode // get posts by ids

If you have no problem with using this shortcode [posts id="1,2,3,4"], the only thing left for you to do is create an array from the id attribute and loop it, like this.

add_shortcode( 'posts', 'posts_shortcode' );
function posts_shortcode($atts) {
    
    $atts = shortcode_atts( array(
        'id' => ''
    ), $atts );
    
    $HTML  = '<div class="posts">';

    foreach (explode(',', $atts['id']) as $post_id) {
        // because now we loop all ids and it can be multiple ids
        // it would be best to warp each one in its own container
        $HTML .='<div class="post">';

        $HTML .= '<div class="thumb">' . get_the_post_thumbnail($post_id, 'medium') . '</div>';
        $HTML .= '<div class="content">';
        $HTML .= '<h4>' . get_the_title($post_id) . '</h4>';
        $HTML .= '<p>' . get_the_excerpt($post_id) . '</p>';
        $HTML .= '</div>';

        // this is the closing tag for our "post" container
        $HTML. ='</div>'; // <div class="post">
    }

    $HTML .= '</div>';
    
    return $HTML; 
} 

The main container <div class="posts"> and its closing tag are outside of the loop because we only want them once.

I’m not sure why you made the varialbe that containes the html all capital letters but for PHP variables, the conventions, is all lowercase letters with underscore, no capital letters.
You are free to use what ever you want of course, but I just wanted to make it clear.